All configuration is written in yaml. It can be loaded either from a local file or Amazon S3 bucket.
When run, parsers will search for configuration in order, once found it will load this configuration. Search order is:
- Local file, when a file name is given via commandline or code
- S3 file, when S3 bucket and key information are given via code
- Local file, when
PYDOMOTIC_CONFIG_FILE
is set - S3 file, when
PYDOMOTIC_CONFIG_S3
is set - Local file
pydomotic.yml
When run via the commandline, the configuration file can be specified as an argument or via environment variable.
$ python -m pydomotic -c /path/to/pydomotic.yml
$ PYDOMOTIC_CONFIG_FILE=/path/to/pydomotic.yml python -m pydomotic
When defined in code, S3 configuration is given as a tuple or string in the form bucket/key
.
handler = LambdaHandler(s3=('my-bucket', 'my-key'))
# or
handler = LambdaHandler(s3='my-bucket/my-key')
Otherwise, it must be given as a string in the form bucket/key
.
$ PYDOMOTIC_CONFIG_S3=my-bucket/my-key python -m pydomotic
Configuration is grouped into four headings: providers, triggers, devices, and automations.
Reading values from environment variables is available in the form of ${env:MY_ENV_VAR}
.
For a complete example configuration file, see tests/testdata/full.yml
.
Currently, four providers are provided out of the box.
- Tuya: Any device that is supported by the Tuya platform. Many IoT manufacturers rely on Tuya for their device APIs. Supported by the
gosundpy
Python package. - Airthings: Any of the Airthings View devices.
- Ecobee: Any Ecobee smart thermostat and sensors.
- Moen: The Flo by Moen smart water shutoff valve.
- Fujitsu: Any Fujitsu WiFi enabled home heat pump system, supported by the
pyfujitseu
Python package. - Noop: A generic provider which can be assigned to any device, useful for testing.
Contributions and requests for further support are welcome.
Each provider relies on its own dependencies which are not installed by default. This means that for each provider you wish to use (aside from the Noop provider), you must specifically install its dependencies. These are installed as pip extras:
$ pip install pydomotic[tuya]
$ pip install pydomotic[airthings]
$ pip install pydomotic[moen]
$ pip install pydomotic[fujitsu]
providers:
tuya:
username: ${env:TUYA_USERNAME}
password: ${env:TUYA_PASSWORD}
access_id: ${env:TUYA_ACCESS_ID}
access_key: ${env:TUYA_ACCESS_KEY}
device_status_cache_seconds: 20
timeout_seconds: 5
devices:
my-device:
description: my cool device
provider: tuya
id: '1234567890'
username: (required) Your Tuya username.
password: (required) Your Tuya password.
access_id: (required) Your Tuya access id.
access_key: (required) Your Tuya access key.
device_status_cache_seconds: (optional) Time in seconds for caching any device statuses. Useful to reduce the number of API calls being made when referencing the same device from multiple components.
timeout_seconds: (optional) Timeout in seconds for all calls to the Tuya API. Defaults to no timeout.
providers:
airthings:
client_id: ${env:AIRTHINGS_CLIENT_ID}
client_secret: ${env:AIRTHINGS_CLIENT_SECRET}
data_cache_seconds: 20
timeout_seconds: 5
devices:
my-device:
description: my cool device
provider: airthings
id: '1234567890'
client_id: (required) Your Airthings client id.
client_secret: (required) Your Airthings client secret.
data_cache_seconds: (optional) Time in seconds for caching any device statuses. Useful to reduce the number of API calls being made when referencing the same device from multiple components.
timeout_seconds: (optional) Timeout in seconds for all calls to the Airthings API. Defaults to no timeout.
providers:
ecobee:
app_key: ${env:ECOBEE_APP_KEY}
refresh_token: ${env:ECOBEE_REFRESH_TOKEN}
devices:
my-device:
description: my cool device
provider: ecobee
id: '1234567890'
app_key: (required) Your Ecobee app key.
refresh_token: (required) Your Ecobee refresh token.
providers:
moen:
username: ${env:MOEN_USERNAME}
password: ${env:MOEN_PASSWORD}
devices:
my-device:
description: my cool device
provider: moen
id: '1234567890'
username: (required) Your Moen username.
password: (required) Your Moen password.
providers:
fujitsu:
username: ${env:FUJITSU_USERNAME}
password: ${env:FUJITSU_PASSWORD}
devices:
my-device:
description: my cool device
provider: fujitsu
id: '1234567890'
username: (required) Your Fujitsu username.
password: (required) Your Fujitsu password.
devices:
my-device:
description: my cool device
provider: noop
id: '1234567890'
Unlike other providers, the noop
provider does not need to be declared in the providers
block.
devices:
my-socket:
description: bedroom window fans
provider: tuya
id: '123'
my-bulb:
description: living room lamp
provider: tuya
id: '456'
my-sensor:
description: basement radon detector
provider: airthings
id: '789'
<name>: (required) Any string value, in the example above my-socket
, my-bulb
, and my-sensor
are all device names.
description: (optional) Any value, used to help identify a device and give it more context.
provider: (required) One of the currently supported providers.
id: (required) The identifier for the device as given by its 3rd party API.
If provided, any further options are ignored.
Automations represent logical groupings of triggers and actions.
automations:
summer:
enabled: true
components:
- if:
temp: '>78'
then:
turn-on: socket-A
else:
turn-off: socket-A
- if:
weekday: saturday,sunday
sunset: -60
then:
turn-on: socket-B
<name>: (required) Any string value, in the example above summer
is the automation name.
<name>.enabled: (optional) When true, the components in this automation will be run, otherwise they will be ignored.
<name>.components: (optional) A list, each item can optionally include if
, then
, and else
keys. The if
is an object containing the triggers to run. When all triggers evaluate to true, the actions contained in the then
object are run. If any of the triggers evaluate to false, the actions contained in the else
object are run.
The top level triggers block contains configuration required for 3rd party APIs.
triggers:
location:
latitude: 40.689
longitude: -74.044
timezone: 'America/New_York'
aqi:
api_key: ${env:AQI_API_KEY}
weather:
api_key: ${env:OPEN_WEATHER_API_KEY}
data_cache_seconds: 20
location.latitude and location.longitude: (optional) The physical location of your home. Required for determining weather, sunrise/sunset times, air quality, and timezone. Either location
or timezone
are required.
timezone: (optional) The timezone of the physical location of your home using the timezone identifier from the IANA database. When not set, location.longitude
and location.latitude
values can be used to determine timezone. However doing so requires installing separate dependencies by running pip install pydomotic[tz]
. These dependencies are not installed by default because they take up significant disk space. Either location
or timezone
are required.
aqi.api_key: (optional) Your API key used to access https://docs.airnowapi.org. Required when using AQI triggers.
weather.api_key: (optional) Your API key used to access https://openweathermap.org. Required when using temperature triggers.
Fires when the outdoor air quality index matches a given value or range of values.
automations:
air-purifier:
enabled: true
components:
- if:
aqi: '>100'
then:
turn-on: switch-A
aqi: (optional) Air quality index to match. Can be single value (ex: 100
), a relative value (ex: >=50
), or a range of values (ex: 50-100
). Multiple values can be given separated by a comma (ex: <50,100-150
).
Fires when the time matches the given value or range of values.
automations:
night-light:
enabled: true
components:
- if:
time: 6:00pm
then:
turn-on: switch-A
time: (optional) Time value to match, in the form of HH:MMpm
. Can be a single value (ex: 5:00am
) or a range of values (ex: 9:00pm-11:00pm
). Multiple values can be given separated by a comma (ex: 4:00am,5:00am,6:30pm
).
Fires when the day of the week matches the given value or range of values.
automations:
party-time:
enabled: true
components:
- if:
weekday: Friday
time: 6:00pm
then:
turn-on: stereo
weekday: (optional) The day of the week value to match. Case insensitive and abreviations supported. Can be a single value (ex: Monday
) or a range of values (ex: mon-fri
). Multiple values can be given separated by a comma (ex: mon,wed,fri
).
Fires when the current date (year, month, day) matches the given value.
automations:
vacation:
enabled: true
components:
- if:
date: 2020-03-20
time: 12:00pm
then:
switch: lightbulb-B
date: (optional) The date value to match, in the form of YYYY-MM-DD
. Multiple values can be given separated by a comma (ex: 2022-01-15,2022-02-15
).
Fires when the given cron expression matches the current date/time.
automations:
fans:
enabled: true
components:
- if:
cron: '*/15 * * * *'
then:
turn-on: socket-A
cron: (optional) Cron expression to match the current date/time. Several predefined shortcuts are supported like @hourly
, @daily
, @weekly
, and @monthly
.
Fires randomly under the given probability.
automations:
vacation:
enabled: true
components:
- if:
random: 0.25
then:
turn-on: socket-A
else:
turn-off: socket-A
random: (optional) The probability between 0 and 1 under which the trigger should fire. The greater the value, the greater the chance the trigger will fire. When 0
the trigger will never fire, when 1
the trigger will always fire, and when 0.5
the trigger will fire one half of the time.
Fires relative to sunrise/sunset time at the current location.
automations:
wake-up:
enabled: true
components:
- if:
weekday: mon-fri
sunrise: 60
then:
turn-on: radio
sunrise or sunset: (optional) Time relative to sunrise/sunset to match. When a positive integer (ex: 90
) will fire that many minutes after sunrise/sunset. When a negative integer (ex: -120
) will fire that many minutes before sunrise/sunset. Can be a single value or a range of values (ex: 45-90
). Multiple values can be given separated by a comma (ex: -15,80
).
Fires when the outdoor temperature matches the given value or range of values.
automations:
air-conditioner:
enabled: true
components:
- if:
temp: '>75'
then:
turn-on: switch-A
temp: (optional) Outdoor temperature value to match. Can be single value (ex: 100
), a relative value (ex: >=50
), or a range of values (ex: 50-100
). Multiple values can be given separated by a comma (ex: <50,90-105
).
Fires when the radon detection level matches the given value or range of values. Only supported as part of a device trigger.
devices:
radon-sensor:
description: radon sensor crawlspace
provider: airthings
id: '1234567890'
automations:
air-purifier:
enabled: true
components:
- if:
radon-sensor:
radon: '>4'
then:
turn-on: switch-A
<name>.radon: (required) Radon level to match in pCi/L. Can be single value (ex: 100
), a relative value (ex: >=50
), or a range of values (ex: 50-100
). Multiple values can be given separated by a comma (ex: <50,100-150
).
Fires when the request path matches the given value. Currently only supported in LambdaHandler
s. Used to remotely trigger an action based on an external event.
automations:
releases:
enabled: true
components:
- if:
webhook: /new-release
then:
turn-on: party-lights
webhook: (optional) Request path to match. Path must match exactly and the request must be a POST
in order to fire.
Fires when the result returned by a sensor matches the given value.
devices:
thermometer:
description: temperature sensor bedroom
provider: tuya
id: '1234567890'
automations:
heatlamp:
enabled: true
components:
- if:
thermometer:
temp: '<60'
then:
turn-on: 'socket-A'
<name>: (optional) The name of the device from which to take the reading.
<name>.<value>: (required) Any of the available triggers as defined above, most commonly temp
and radon
.
Depending on the device and its provider, the following actions are available.
Turns on/off the given device.
automations:
bedroom:
enabled: true
components:
- if:
time: 10:00am-12:00pm
then:
turn-on: 'socket-A'
else:
turn-off: 'socket-A'
turn-on and turn-off: (optional) Matches device name as defined in the devices section.
Switches the state of the given device.
automations:
vacation:
enabled: true
components:
- if:
random: 0.10
then:
switch: 'socket-A'
switch: (optional) Matches device name as defined in the devices section.
Sets the current mode for a Flo by Moen device.
devices:
flo:
description: Flo by Moen
provider: moen
id: '1234567890'
automations:
vacation:
enabled: true
components:
- if:
date: 2020-03-20
time: 7:00am
then:
set-mode:
device: flo
mode: sleep
revert-min: 60
revert-mode: away
set-mode.device: (required) Name of the device whose mode to change.
set-mode.mode: (required) The mode to change to, one of home
, away
, or sleep
.
set-mode.revert-min: (optional) When changing to sleep
mode, minutes to wait before automatically reverting mode. Defaults to 480 minutes (8 hours).
set-mode.revert-mode: (optional) When changing to sleep
mode, mode to revert to after completion of the sleep, one of home
or away
. Defaults to home
.
Lazy loads and executes the given Python method.
devices:
radon-sensor:
description: basement radon
provider: airthings
id: '1234567890'
automations:
radon-alert:
enabled: true
components:
- if:
radon-sensor:
radon: '>4'
then:
exec: custom_actions.send_email
exec: (optional) The module and method name to execute in the form of module.method
. Multiple values can be given separated by a comma (ex: custom_actions.turn_on,custom_actions.send_email
). Method must accept just one argument, the context
object which holds references to all configured sensors and devices. For example:
# custom_actions.py
import boto3
client = boto3.client('ses')
def send_email(context):
radon = context.devices['radon-sensor'].current_radon()
client.send_email(
Source='[email protected]',
Destination={
'ToAddresses': ['[email protected]'],
},
Message={
'Subject': {'Data': 'Radon levels too high!'},
'Body': {
'Text': {'Data': f'The current radon level is {radon}.'},
},
},
)
Aliases are a way to group sections of your configuration file under a single name to be referenced later.
Device aliases allow you to use a custom name to represent a group of devices. This is useful if you wish to group devices together and reference them by a single name.
For example, consider the following configuration:
automations:
lighting:
enabled: true
components:
- if:
sunset: -60
then:
turn-on: light-A, light-B, light-C
- if:
time: 11:00pm
then:
turn-off: light-A, light-B, light-C
fan:
enabled: true
components:
- if:
temp: '>78'
then:
turn-on: fan-A, fan-B, fan-C
- if:
time: 11:00pm
then:
turn-off: fan-A, fan-B, fan-C
But now, if you ever wish to add another light to the group, you would need to update all the automations that reference the group. Instead, you can use an alias and only define the group of devices once:
aliases:
devices:
lights:
- light-A
- light-B
- light-C
fans:
- fan-A
- fan-B
- fan-C
automations:
lighting:
enabled: true
components:
- if:
sunset: -60
then:
turn-on: lights
- if:
time: 11:00pm
then:
turn-off: lights
fan:
enabled: true
components:
- if:
temp: '>78'
then:
turn-on: fans
- if:
time: 11:00pm
then:
turn-off: fans