{"id":47091902,"url":"https://github.com/GeiserX/PiSpot-Show","last_synced_at":"2026-03-26T15:00:56.764Z","repository":{"id":292586579,"uuid":"981337560","full_name":"GeiserX/PiSpot-Show","owner":"GeiserX","description":"Raspberry Pi WiFi voucher display system with weather integration and PiJuice battery management","archived":false,"fork":false,"pushed_at":"2026-03-10T13:22:14.000Z","size":11819,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-03-10T16:07:56.135Z","etag":null,"topics":["battery","captive-portal","digital-signage","display","embedded","hdmi","hospitality","hotel","hotspot","iot","kiosk","linux","pijuice","pispot","portable","python","raspberry-pi","ups","voucher","wifi"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GeiserX.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"geiserx","patreon":"geiser","buy_me_a_coffee":"geiser","thanks_dev":"u/gh/geiserx"}},"created_at":"2025-05-10T21:54:34.000Z","updated_at":"2026-03-10T13:22:18.000Z","dependencies_parsed_at":"2025-05-10T23:28:11.646Z","dependency_job_id":null,"html_url":"https://github.com/GeiserX/PiSpot-Show","commit_stats":null,"previous_names":["geiserx/pispot-show"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/GeiserX/PiSpot-Show","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPiSpot-Show","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPiSpot-Show/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPiSpot-Show/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPiSpot-Show/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GeiserX","download_url":"https://codeload.github.com/GeiserX/PiSpot-Show/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GeiserX%2FPiSpot-Show/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30972995,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-26T14:13:19.610Z","status":"ssl_error","status_checked_at":"2026-03-26T14:12:43.279Z","response_time":114,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["battery","captive-portal","digital-signage","display","embedded","hdmi","hospitality","hotel","hotspot","iot","kiosk","linux","pijuice","pispot","portable","python","raspberry-pi","ups","voucher","wifi"],"created_at":"2026-03-12T11:00:28.635Z","updated_at":"2026-03-26T15:00:56.740Z","avatar_url":"https://github.com/GeiserX.png","language":"Python","readme":"\u003cp align=\"center\"\u003e\u003cimg src=\"docs/images/banner.svg\" alt=\"PiSpot Show banner\" width=\"900\"/\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\u003cimg src=\"https://github.com/GeiserX/PiSpot-Show/blob/main/extra/logo.jpg?raw=true\" width=\"128\" height=\"128\" alt=\"PiSpot Show logo\"/\u003e\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003ePiSpot Show\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eTurn any HDMI display into a self-updating Wi-Fi voucher kiosk with live weather, powered by Raspberry Pi.\u003c/strong\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/GeiserX/PiSpot-Show/blob/main/LICENSE\"\u003e\u003cimg src=\"https://img.shields.io/github/license/GeiserX/PiSpot-Show\" alt=\"License: GPL-3.0\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.raspberrypi.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/platform-Raspberry%20Pi-C51A4A?logo=raspberrypi\u0026logoColor=white\" alt=\"Raspberry Pi\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.python.org/\"\u003e\u003cimg src=\"https://img.shields.io/badge/python-3.x-3776AB?logo=python\u0026logoColor=white\" alt=\"Python 3\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://www.ansible.com/\"\u003e\u003cimg src=\"https://img.shields.io/badge/deploy-Ansible-EE0000?logo=ansible\u0026logoColor=white\" alt=\"Ansible\"/\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/PiSupply/PiJuice\"\u003e\u003cimg src=\"https://img.shields.io/badge/power-PiJuice%20HAT-1B5E20\" alt=\"PiJuice HAT\"/\u003e\u003c/a\u003e\n\u003c/p\u003e\n\n---\n\n## Overview\n\nPiSpot Show is a headless Raspberry Pi appliance that drives hotel lobby TVs and public-area monitors. Every hour it generates a fresh time-limited Wi-Fi voucher from the [Spotipo](https://www.spotipo.com/) captive-portal API, pulls a live weather forecast, and composites everything into a branded Full-HD image rendered directly to the Linux framebuffer -- no desktop environment required.\n\nA [PiJuice HAT](https://github.com/PiSupply/PiJuice) provides battery-backed power management with RTC wake/sleep scheduling, a hardware watchdog, and graceful low-voltage shutdown, making the device suitable for unattended 24/7 operation.\n\nOriginally developed and deployed in 2018 for the company GPConnect. Part of the **PiSpot ecosystem**:\n\n| Project | Description |\n|---|---|\n| [PiSpot Watch](https://github.com/GeiserX/PiSpot-Watch) | Wrist-wearable e-ink voucher device |\n| **PiSpot Show** (this repo) | HDMI kiosk display for lobby TVs |\n| [PiSpot Deployment](https://github.com/GeiserX/PiSpot-Deployment) | Fleet provisioning and Vault configuration |\n\n---\n\n## Features\n\n- **Hourly voucher rotation** -- generates a new Spotipo Wi-Fi voucher every hour with configurable duration, speed limits, device caps, and data quotas.\n- **Live weather overlay** -- fetches temperature, \"feels like\", daily min/max, conditions, and forecast summary from the Dark Sky API with matching weather icons.\n- **Full-HD branded output** -- 1920x1080 image composited with Pillow using custom Raleway typography, logos, SSID, voucher code, weather data, and current date.\n- **Framebuffer rendering** -- pushes images directly to `/dev/fb0` via `fbi`, bypassing X11/Wayland entirely for a minimal, kiosk-grade display pipeline.\n- **PiJuice power management** -- battery UPS with RTC wake-up alarms (e.g. 09:00 weekdays), scheduled shutdown via cron, hardware watchdog (5s), wake-on-charge at 20%.\n- **Boot splash screen** -- displays branding immediately on power-on via a dedicated systemd unit, before the main service starts.\n- **Ansible deployment** -- single playbook provisions packages, creates users, generates SSH keys, clones the repo, registers services, configures WiFi, and optimizes GPU/USB power.\n- **3D-printable enclosure** -- FreeCAD parametric designs and ready-to-print STLs for a custom case with button panel and lid.\n- **Error resilience** -- on API failure, renders an error screen and retries after 60 seconds without crashing.\n\n---\n\n## Videos\n\n### In Action\n\n[![PiSpot Show In Action](http://img.youtube.com/vi/Uocjf3nof9g/0.jpg)](http://www.youtube.com/watch?v=Uocjf3nof9g \"PiSpot Show In Action\")\n\n### Assembly\n\n[![PiSpot Show Assembly](http://img.youtube.com/vi/0NGtbnZm6PA/0.jpg)](http://www.youtube.com/watch?v=0NGtbnZm6PA \"PiSpot Show Assembly\")\n\n---\n\n## Photos\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/photos/hdmi-display-voucher-rain-weather.jpg\" width=\"400\" alt=\"HDMI display showing voucher with rain weather\"/\u003e\n  \u003cimg src=\"docs/photos/hdmi-display-voucher-sunny-weather.jpg\" width=\"400\" alt=\"HDMI display showing voucher with sunny weather\"/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/photos/pi3-pijuice-hat-in-case.jpg\" width=\"300\" alt=\"Raspberry Pi 3 with PiJuice HAT\"/\u003e\n  \u003cimg src=\"docs/photos/blue-case-buttons-front.jpg\" width=\"300\" alt=\"Blue 3D-printed case with buttons\"/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"docs/photos/white-case-buttons-side.jpg\" width=\"300\" alt=\"White case with buttons\"/\u003e\n  \u003cimg src=\"docs/photos/three-blue-cases-fleet.jpg\" width=\"300\" alt=\"Fleet of three blue cases\"/\u003e\n\u003c/p\u003e\n\nSee all photos in [`docs/photos/`](docs/photos/).\n\n---\n\n## Architecture\n\n```\n                         +------------------+\n                         |   HDMI Display   |\n                         |   (1920x1080)    |\n                         +--------+---------+\n                                  |\n                         +--------+---------+\n                         |   Raspberry Pi   |\n                         |   + PiJuice HAT  |\n                         +--+-----+------+--+\n                            |     |      |\n                  +---------+  +--+--+  ++----------+\n                  |            |     |  |            |\n          +-------v---+ +-----v-+ +-v--v------+ +---v--------+\n          | Spotipo   | | Dark  | | Pillow    | | fbi        |\n          | WiFi API  | | Sky   | | (image    | | (framebuf  |\n          | (voucher) | | (wx)  | |  render)  | |  display)  |\n          +-----------+ +-------+ +-----------+ +------------+\n```\n\n1. **main.py** runs in an infinite loop as a systemd service.\n2. Each hour, it POSTs to the Spotipo API to create a time-limited voucher.\n3. It GETs the current weather from Dark Sky (with localized language support).\n4. Pillow composites the voucher code, SSID, weather data, date, and branding onto a 1920x1080 PNG.\n5. `fbi` pushes the image to the Linux framebuffer.\n6. **piJuice_stop.py** is called via cron to trigger a timed shutdown; the PiJuice RTC alarm handles the next wake-up.\n\n---\n\n## Hardware\n\n| Component | Purpose |\n|---|---|\n| Raspberry Pi 3 (or later) | Main compute board |\n| PiJuice HAT (1680 mAh) | Battery UPS, RTC alarms, watchdog, wake-on-charge |\n| HDMI display (TV or monitor) | Guest-facing 1920x1080 voucher screen |\n| MicroSD card (8 GB+) | Raspbian OS + application |\n| Power supply (5 V / 2.5 A) | Board + HAT power |\n\n---\n\n## Getting Started\n\n### 1. Clone\n\n```bash\ngit clone https://github.com/GeiserX/PiSpot-Show.git\ncd PiSpot-Show\n```\n\n### 2. Configure API keys\n\nEdit `main.py` and set your credentials:\n\n```python\nSpotipo_Key  = \"YOUR-SPOTIPO-TOKEN\"\nDarksky_Key  = \"YOUR-DARKSKY-KEY\"\n```\n\nAlso update the Spotipo endpoint URL, SSID name, and weather coordinates.\n\n### 3. Deploy with Ansible\n\n```bash\nansible-playbook -i inventory deployment-files/main.yml\n```\n\nThe playbook handles: system packages (`fbi`, `pijuice-base`, `imagemagick`), Python dependencies, dedicated user with scoped sudo, SSH key generation, service registration, WiFi, timezone, and GPU/USB power optimization.\n\n### 4. Configure PiJuice schedule\n\nSet the RTC wake alarm via `pijuice_cli` (e.g. 09:00 weekdays) and add the shutdown cron:\n\n```bash\ncrontab -e\n# 0 17 * * * /usr/bin/python3 /opt/PiSpot_HDMI/piJuice_stop.py\n```\n\n---\n\n## Configuration\n\n### Voucher parameters\n\nSet in the API request body inside `main.py`:\n\n| Parameter | Default | Description |\n|---|---|---|\n| `duration_val` | `4` | Voucher validity period |\n| `duration_type` | `2` | Duration unit (1=min, 2=hour, 3=day) |\n| `num_devices` | `10` | Max concurrent devices per voucher |\n| `speed_dl` | `1024` | Download speed limit (Kbps) |\n| `speed_ul` | `256` | Upload speed limit (Kbps) |\n| `bytes_t` | `0` | Data cap (0 = unlimited) |\n\n### PiJuice events\n\nDefined in `pijuice_config.JSON`:\n\n- **Low battery** -- halt and power off\n- **Watchdog reset** -- automatic reboot (5s period)\n- **Wake-on-charge** -- boot at 20% battery\n- **Button / forced power off** -- graceful halt\n\n---\n\n## 3D-Printable Enclosure\n\nThe `Case/` directory contains a complete enclosure designed in FreeCAD:\n\n| File | Description |\n|---|---|\n| `Caja.stl` | Main housing body |\n| `Tapa.stl` | Top lid / cover |\n| `Botonera.stl` | Button panel insert |\n| `*.fcstd` | FreeCAD parametric source files |\n| `*.gx` | Goxel voxel models |\n\n---\n\n## Project Structure\n\n```\nPiSpot-Show/\n  main.py                    # Main loop: voucher + weather + render + display\n  piJuice_stop.py            # Scheduled shutdown script\n  pijuice_config.JSON        # PiJuice HAT event/watchdog configuration\n  fonts/                     # Raleway Light + Black typeface\n  images/                    # Backgrounds, logos, weather icons, generated output\n  servicefiles/\n    pispot_hdmi.service      # Main application systemd unit\n    splashscreen.service     # Boot splash systemd unit\n  deployment-files/\n    main.yml                 # Ansible provisioning playbook\n    wpa_supplicant.conf      # WiFi network configuration\n    GitLabANDHostname.py     # SSH key + hostname setup for fleet devices\n  Case/                      # 3D enclosure (FreeCAD + Goxel + STL)\n  LICENSE                    # GPL-3.0\n```\n\n---\n\n## License\n\n[GNU General Public License v3.0](LICENSE)\n\n## Maintainers\n\n[@GeiserX](https://github.com/GeiserX)\n\n## Contributing\n\nContributions are welcome. [Open an issue](https://github.com/GeiserX/PiSpot-Show/issues/new) or submit a pull request.\n\nThis project follows the [Contributor Covenant v2.1](https://www.contributor-covenant.org/version/2/1/code_of_conduct/) Code of Conduct.\n","funding_links":["https://github.com/sponsors/geiserx","https://patreon.com/geiser","https://buymeacoffee.com/geiser","https://thanks.dev/u/gh/geiserx"],"categories":["gadget","Raspberry","Projects","Library","Table of Contents"],"sub_categories":["USB GADGET","ESP8266","Low Level","Hardware"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGeiserX%2FPiSpot-Show","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGeiserX%2FPiSpot-Show","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGeiserX%2FPiSpot-Show/lists"}