{"id":23991301,"url":"https://github.com/loglux/blackbincollection","last_synced_at":"2026-05-08T06:04:29.324Z","repository":{"id":169714350,"uuid":"410010476","full_name":"loglux/BlackBinCollection","owner":"loglux","description":"The script takes the next Black Bin collection date information from the Belfast City Hall Website and then publishes the event in your Outlook Calendar.","archived":false,"fork":false,"pushed_at":"2024-07-11T18:08:04.000Z","size":18,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-07T19:39:30.916Z","etag":null,"topics":["automation","belfast","bin-collection-app","docker","outlook-calendar","scrapping-python","selenium","selenium-grid"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/loglux.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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}},"created_at":"2021-09-24T15:17:46.000Z","updated_at":"2024-07-11T18:08:07.000Z","dependencies_parsed_at":null,"dependency_job_id":"14b503cd-897a-4d36-81eb-8b3afa338c6f","html_url":"https://github.com/loglux/BlackBinCollection","commit_stats":null,"previous_names":["loglux/blackbincollection"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loglux%2FBlackBinCollection","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loglux%2FBlackBinCollection/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loglux%2FBlackBinCollection/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/loglux%2FBlackBinCollection/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/loglux","download_url":"https://codeload.github.com/loglux/BlackBinCollection/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240605841,"owners_count":19827985,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["automation","belfast","bin-collection-app","docker","outlook-calendar","scrapping-python","selenium","selenium-grid"],"created_at":"2025-01-07T19:39:03.757Z","updated_at":"2026-05-08T06:04:29.316Z","avatar_url":"https://github.com/loglux.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# BlackBin - Belfast Bin Collection Tracker\n\nAutomates checking the next Black Bin collection day for a Belfast address (via Belfast City Council site), adds it to your calendar (Outlook/Google), and can publish updates to Home Assistant (MQTT/webhook/REST).\n\n## Tech Stack\n\n![Python](https://img.shields.io/badge/Python-3.11+-3776AB?style=for-the-badge\u0026logo=python\u0026logoColor=white)\n![Docker](https://img.shields.io/badge/Docker-2496ED?style=for-the-badge\u0026logo=docker\u0026logoColor=white)\n![Selenium](https://img.shields.io/badge/Selenium-43B02A?style=for-the-badge\u0026logo=selenium\u0026logoColor=white)\n![Flask](https://img.shields.io/badge/Flask-000000?style=for-the-badge\u0026logo=flask\u0026logoColor=white)\n![Microsoft](https://img.shields.io/badge/Microsoft_Graph-0078D4?style=for-the-badge\u0026logo=microsoft\u0026logoColor=white)\n![Google Calendar](https://img.shields.io/badge/Google_Calendar-4285F4?style=for-the-badge\u0026logo=google-calendar\u0026logoColor=white)\n![Home Assistant](https://img.shields.io/badge/Home_Assistant-41BDF5?style=for-the-badge\u0026logo=home-assistant\u0026logoColor=white)\n![MQTT](https://img.shields.io/badge/MQTT-660066?style=for-the-badge\u0026logo=mqtt\u0026logoColor=white)\n\n## Requirements\n\n- Docker\n- Optional: Python 3.11+ (for non-Docker runs)\n\n## Status\n\n| Integration | Status |\n|-------------|--------|\n| Selenium scraping | OK |\n| Outlook Calendar | OK (automatic token refresh) |\n| MQTT | OK (Home Assistant auto-discovery) |\n| Google Calendar | OK (service account) |\n| HA Webhook | Available (disabled by default) |\n| REST API | Available (disabled by default) |\n\n## Quick Start (Docker)\n\n```bash\n# 1. Copy environment template\ncp .env.example .env\n\n# 2. Start containers (choose one)\n./docker_start.sh          # host network\n./doc_start.sh             # bridge network\n\n# 3. Open Web UI\nhttp://\u003cyour-ip\u003e:5050\n```\n\nConfig is stored in `/data/blackbin_config.json` and survives container rebuilds.\n\n---\n\n## Configuration\n\n### Option 1: Web UI (recommended)\n\nOpen `http://\u003cyour-ip\u003e:5050` in a browser. All settings are available:\n\n- **Address** — postcode lookup, address selection, validation\n- **Schedule** — visual day/time picker for cron jobs\n- **MQTT** — broker, port, credentials, topic\n- **Outlook Calendar** — client ID, token generation, calendar selection\n- **Google Calendar** — upload service account JSON, calendar selection\n\nChanges are saved to `/data/blackbin_config.json` and applied immediately.\n\n### Option 2: Console (--configure)\n\nInteractive prompts for headless setup:\n\n```bash\ndocker exec -it blackbin python blackbin.py --configure\n```\n\nConfigures: address, schedule, MQTT. Calendar settings require Web UI or `.env`.\n\n### Option 3: Environment Variables (.env)\n\nFor automation (Docker Compose, Kubernetes). See `.env.example` for full list.\n\nKey variables:\n\n```dotenv\n# Outlook\nCLIENT_ID=your_client_id\nCLIENT_SECRET=your_client_secret\nTENANT_ID=common\nENABLE_OUTLOOK=true\n\n# Google Calendar\nENABLE_GOOGLE_CALENDAR=false\nGOOGLE_SERVICE_ACCOUNT_FILE=google_service_account.json\nGOOGLE_CALENDAR_ID=primary\n\n# MQTT\nENABLE_MQTT=false\nMQTT_BROKER=192.168.1.10\nMQTT_PORT=1883\nMQTT_USERNAME=\nMQTT_PASSWORD=\n\n# Selenium\nSELENIUM_HOST=localhost\nSELENIUM_PORT=4444\n```\n\n**Precedence:** config file values override `.env`.\n\n---\n\n## Feature Flags\n\nEnable/disable modules via `.env` or Web UI:\n\n| Flag | Default | Description |\n|------|---------|-------------|\n| `ENABLE_WEB_UI` | `true` | Web interface on port 5050 |\n| `ENABLE_OUTLOOK` | `true` | Outlook Calendar integration |\n| `ENABLE_GOOGLE_CALENDAR` | `false` | Google Calendar integration |\n| `ENABLE_MQTT` | `false` | MQTT publisher (Home Assistant) |\n| `ENABLE_HA_WEBHOOK` | `false` | Home Assistant webhook notifier |\n| `ENABLE_REST_API` | `false` | REST API endpoint |\n\nExample — run with only MQTT, no calendars:\n\n```bash\ndocker run -d --name blackbin \\\n  -e ENABLE_OUTLOOK=false \\\n  -e ENABLE_MQTT=true \\\n  -e MQTT_BROKER=192.168.1.10 \\\n  -v ./data:/data \\\n  blackbin\n```\n\n---\n\n## Integrations\n\n### Outlook Calendar\n\n**Azure Portal setup:**\n\n1. Create an app registration in [Azure Portal](https://portal.azure.com)\n2. Set supported account types (use `common` for personal accounts)\n3. Add delegated API permissions: `Calendars.ReadWrite`, `User.Read`, `offline_access`\n4. Enable \"Allow public client flows\" (for device code auth)\n\n**Token generation (Web UI):**\n\n1. Enter Client ID and Tenant ID in Outlook section\n2. Click \"Generate token\" under \"Token setup / refresh\"\n3. Open the verification URL, enter the code\n4. Click \"Complete sign-in\" — token saved to `/data/o365_token.txt`\n\n**Token generation (console):**\n\n```bash\ndocker exec -it blackbin python auth_msal.py\n```\n\n**Calendar selection:**\n\n- Click \"Fetch calendars\" to load your calendars\n- Select from dropdown — ID fills automatically\n- Or leave empty for default calendar\n\n**Token lifespan:**\n\n- Access tokens expire in ~1 hour (auto-refreshed)\n- Refresh tokens last ~90 days (sliding window)\n- Re-run token flow only if refresh fails\n\n---\n\n### Google Calendar\n\n**Google Cloud setup:**\n\n1. Create a project in [Google Cloud Console](https://console.cloud.google.com)\n2. Enable Google Calendar API\n3. Create a Service Account (IAM → Service Accounts)\n4. Download JSON key, save as `google_service_account.json`\n\n**Share calendar with Service Account:**\n\n1. Find service account email in JSON file (field `client_email`):\n   ```\n   blackbin-calendar@my-project-123456.iam.gserviceaccount.com\n   ```\n2. Open [Google Calendar](https://calendar.google.com)\n3. Settings → select your calendar\n4. \"Share with specific people or groups\" → Add people\n5. Paste service account email\n6. Permission: **\"Make changes to events\"**\n7. Click Send\n\n**Calendar selection (Web UI):**\n\n1. Upload service account JSON\n2. Click \"Fetch calendars\"\n3. Select calendar from dropdown\n\n**Important — calendars don't appear automatically:**\n\nShared calendars don't auto-appear in Service Account's list. If \"Fetch calendars\" returns empty:\n\n```bash\ndocker exec blackbin python -c \"\nfrom integrations.google_calendar import GoogleCalendar\ngc = GoogleCalendar('/data/google_service_account.json')\ncalendar_id = 'YOUR_CALENDAR_ID@group.calendar.google.com'\ngc.service.calendarList().insert(body={'id': calendar_id}).execute()\nprint('Calendar added!')\n\"\n```\n\nGet Calendar ID: Google Calendar → Settings → Integrate calendar.\n- Custom calendars: `abc123...@group.calendar.google.com`\n- Primary calendar: `primary` or owner's email\n\n**Reminders/Notifications:**\n\nGoogle reminders are per-user. Service Account reminders won't notify you.\n\nConfigure default notifications in your calendar:\n1. Google Calendar → Settings → your calendar\n2. \"Event notifications\" section\n3. Add notification (e.g., 6 hours before)\n\n---\n\n### MQTT (Home Assistant)\n\nPublishes to Home Assistant via MQTT auto-discovery.\n\n**Topics:**\n\n- `homeassistant/sensor/blackbin/config` — discovery config\n- `homeassistant/sensor/blackbin/state` — date (`YYYY-MM-DD`)\n- `homeassistant/sensor/blackbin/attributes` — JSON metadata\n\n**Setup:**\n\n1. Enable MQTT in Web UI or `.env`\n2. Set broker address, port, credentials\n3. Entity `sensor.black_bin_collection` appears in Home Assistant\n\n**Custom date format:**\n\nSet `MQTT_STATE_FORMAT` (strftime), e.g., `%a %d %b` → \"Wed 29 Jan\"\n\n**Home Assistant template (friendly date):**\n\n```yaml\ntemplate:\n  - sensor:\n      - name: \"Black Bin Collection Friendly\"\n        state: \u003e\n          {% set raw = states('sensor.black_bin_collection') %}\n          {% if raw in ['unknown','unavailable','none',''] %}\n            unknown\n          {% else %}\n            {% set dt = as_datetime(raw) %}\n            {% set dow = ['Mon','Tue','Wed','Thu','Fri','Sat','Sun'][dt.weekday()] %}\n            {% set mon = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'][dt.month-1] %}\n            {{ dow }} {{ '%02d'|format(dt.day) }} {{ mon }}\n          {% endif %}\n```\n\n---\n\n## Docker Setup\n\n### Host network\n\n```bash\ndocker run -d --name selenium-server --network host selenium/standalone-chrome\nmkdir -p data\ndocker build -t blackbin .\ndocker run -d --name blackbin --network host -v ./data:/data blackbin\n```\n\n### Bridge network\n\n```bash\ndocker network create selenium-network\ndocker run -d --name selenium-server --network selenium-network \\\n  -p 4444:4444 -p 7900:7900 --shm-size=\"2g\" selenium/standalone-chrome\nmkdir -p data\ndocker build -t blackbin .\ndocker run -d --name blackbin --network selenium-network \\\n  -e SELENIUM_HOST=selenium-server -p 5050:5050 -v ./data:/data blackbin\n```\n\n### Stop and remove\n\n```bash\ndocker stop blackbin selenium-server\ndocker rm blackbin selenium-server\n```\n\n---\n\n## Run without Docker\n\n```bash\n# Install dependencies\npip install -r requirements.txt\n\n# Start Selenium\ndocker run -d --name selenium-server -p 4444:4444 selenium/standalone-chrome\n\n# Configure\nexport CONFIG_PATH=./blackbin_config.json\npython blackbin.py --configure\n\n# Run\npython blackbin.py\n\n# Web UI (optional)\npython web_ui.py\n```\n\n---\n\n## Schedule\n\nDefault cron: Monday, Friday, Saturday at 19:30; Wednesday at 03:30.\n\nView current schedule:\n\n```bash\ndocker exec blackbin crontab -l\n```\n\nOverride via environment:\n\n```bash\nCRON_SCHEDULES=\"30 19 * * 1,5,6;30 3 * * 3\"\n```\n\nSchedules set in Web UI apply immediately. Manual edits require container restart.\n\n---\n\n## Project Structure\n\n```\nblackbin/\n├── blackbin.py              # Main script\n├── web_ui.py                # Flask Web UI\n├── integrations/\n│   ├── outlook_calendar.py  # Outlook integration\n│   ├── google_calendar.py   # Google Calendar integration\n│   └── notifiers/           # MQTT, webhook, REST\n├── templates/               # Web UI templates\n├── data/                    # Config and tokens (mounted volume)\n├── Dockerfile\n├── docker_start.sh          # Host network launcher\n├── doc_start.sh             # Bridge network launcher\n├── .env.example             # Environment template\n└── requirements.txt\n```\n\n---\n\n## Secrets (do not commit)\n\n- `.env` — credentials and flags\n- `o365_token.txt` — Outlook OAuth token\n- `google_service_account.json` — Google credentials\n- `data/blackbin_config.json` — runtime config\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floglux%2Fblackbincollection","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Floglux%2Fblackbincollection","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Floglux%2Fblackbincollection/lists"}