Small python tool to forward stock of you favourite stores to Home Assistant via MQTT.
Stores are automatically created via MQTT Discovery and contain some addition attributes like price and more.
Easiest way is to use the Home Assistant Add-on. I created one in my Home Assistant Add-on repository.
Docker image is created automatically and available at dockerhub: maxwinterstein/toogoodtogo-ha-mqtt-bridge
This project uses some awesome tools for better developer expirence:
None of this is required to run it natively, but makes the job a lot easier.
There are multiples ways to get going, some of the fastest might be using pkgx
and direnv
.
Having both pre-installed on your machine (see related docs) will get you going this quick:
- Adjust
settings.local.json
- see below - Start a pkgx dev environment
dev # provided by pkgx - will read pkgx.yaml and install deps
- Run it though Taskfile (the better Makefile INHO)
task run
Not needed when using HA Add-On
Create some settings file called settings.local.json
(see settings.example.json
):
{
"mqtt": {
"host": "homeassistant.local",
"port": 1883,
"username": "mqtt",
"password": "mqtt"
},
"tgtg": {
"email": "[email protected]",
"language": "en-US",
"polling_schedule": "*/10 * * * *",
"intense_fetch": { "interval": 30, "period_of_time": 5 }
},
"timezone": "Europe/Berlin",
"locale": "en_us"
}
sets the polling interval in cron notation. For more Infomation have a look here: https://crontab.guru/
Is meant query your favourites for a short amount of time with a higher frequency.
Ideal for those boxes you always miss!
With the interval
, the time between the queries can be controlled.
With the setting period_of_time
the duration of the intense fetch can be defined.
The smallest interval is 10 seconds, and the maximum duration of the intense_fetch is 60 minutes.
Attention: This is meant for expierenced users as you might get blocked for a certain amount of time by toogoodtogo.
When enabled, above mentioned intense_fetch
will be started automatically when a shops sales window (automatically created portions) starts.
We add some jitter on the fetch interval, so not everyone hits the poor API at the same second.
as TooGoodToGo provides its times as UTC we format it to local time. See Wikipedia for valid values.
to format pickup times like in 2 hours. E.g. de
for german, en_us
for american english.
remove items from Home Assistant if they are no longer in the fetched result.
folder to store persistent data. Needed e.g. for cleanup
feature.
And start with the mounted settings file, e.g. for macOS:
docker run --rm -ti --pull always -v $PWD/settings.local.json:/app/settings.local.json -v $PWD/data/:/data -v /etc/localtime:/etc/localtime:ro maxwinterstein/toogoodtogo-ha-mqtt-bridge
Or using docker-compose:
version: "3"
services:
toogoodtogo-bridge:
image: maxwinterstein/toogoodtogo-ha-mqtt-bridge
container_name: toogoodtogo-bridge
volumes:
- ./settings.local.json:/app/settings.local.json
- ./data:/data
- /etc/localtime:/etc/localtime:ro
restart: unless-stopped
Attributes are used to keep the amount of sensors small. If you want some specific sensor you can create it as template sensor.
sensor:
- platform: template
sensors:
toogoodtogo_eilles_frankfurt_price:
unit_of_measurement: "€"
icon_template: mdi:currency-eur
friendly_name: "Eilles Frankfurt Price"
value_template: "{{ state_attr('sensor.toogoodtogo_eilles_frankfurt', 'price') }}"
Add the following piece of code into /developer-tools/template in HomeAssistant. (Remove the last comma)
{%- for state in states -%}
{%- if (state.entity_id.startswith('sensor.toogoodtogo_'))-%}
{{state.entity_id}},
{%- endif -%}
{%- endfor -%}
alias: TooGoodToGo Notification
description: "Sends a notification when a toogoodtogo offer becomes available"
trigger:
- platform: state
entity_id:
>- # This is your list of toogoodoto sensors which are generated (Copy paste the list from above)
sensor.toogoodtogo_1,sensor.toogoodtogo_2,sensor.toogoodtogo_3
attribute: stock_available
from: false
to: true
condition: []
action:
- service: notify.mobile_app_android
data:
message: >-
Available: {{trigger.to_state.state}}, For:
{{trigger.to_state.attributes.price}} in
{{trigger.to_state.attributes.pickup_start_human}}
title: "{{trigger.to_state.attributes.friendly_name}}"
data:
clickAction: "{{trigger.to_state.attributes.url}}"
image: "{{trigger.to_state.attributes.picture}}"
group: tgtg
tag: "{{trigger.entity_id}}"
- service: notify.mobile_app_iphone
data:
message: >-
Available: {{trigger.to_state.state}}, For:
{{trigger.to_state.attributes.price}} in
{{trigger.to_state.attributes.pickup_start_human}},
{{trigger.to_state.attributes.friendly_name}}
title: "{{trigger.to_state.attributes.friendly_name}}"
data:
url: "{{trigger.to_state.attributes.url}}"
image: "{{trigger.to_state.attributes.picture}}"
group: tgtg
tag: "{{trigger.entity_id}}"
mode: parallel
max: 10
alias: TooGoodToGo UnNotification
description: ""
trigger:
- platform: state
entity_id:
>- # This is your list of toogoodoto sensors which are generated (Copy paste the list from above)
sensor.toogoodtogo_1,sensor.toogoodtogo_2,sensor.toogoodtogo_3
attribute: stock_available
from: true
to: false
condition: []
action:
- service: notify.mobile_app_android
data:
message: clear_notification
data:
tag: "{{trigger.entity_id}}"
- service: notify.mobile_app_iphone
data:
message: clear_notification
data:
tag: "{{trigger.entity_id}}"
mode: parallel
max: 10
This project uses pre-commit to make sure the code keeps clean and similar. Usage is highly advised.