"""This script adds MQTT discovery support for Shellies devices.""" ATTR_ICON = "icon" ATTR_MANUFACTURER = "Allterco Robotics" ATTR_POWER_AC = "ac" ATTR_RELAY = "relay" ATTR_ROLLER = "roller" ATTR_SHELLY = "Shelly" BUTTON_MUTE = "mute" BUTTON_RESTART = "restart" BUTTON_SELF_TEST = "self_test" BUTTON_UNMUTE = "unmute" BUTTON_UPDATE_FIRMWARE = "update_firmware" BUTTON_VALVE_CLOSE = "valve_close" BUTTON_VALVE_OPEN = "valve_open" COMP_FAN = "fan" COMP_LIGHT = "light" COMP_SWITCH = "switch" CONF_DEVELOP = "develop" CONF_DEVICE_NAME = "device_name" CONF_DISCOVERY_PREFIX = "discovery_prefix" CONF_EXPIRE_AFTER = "expire_after" CONF_EXT_SWITCH = "ext-switch" CONF_FORCE_UPDATE_SENSORS = "force_update_sensors" CONF_FRIENDLY_NAME = "friendly_name" CONF_FW_VER = "fw_ver" CONF_HOST = "host" CONF_ID = "id" CONF_IGNORE_DEVICE_MODEL = "ignore_device_model" CONF_IGNORED_DEVICES = "ignored_devices" CONF_MAC = "mac" CONF_MODE = "mode" CONF_MODEL_ID = "model" CONF_OPTIMISTIC = "optimistic" CONF_POSITION_TEMPLATE = "position_template" CONF_POWERED = "powered" CONF_PUSH_OFF_DELAY = "push_off_delay" CONF_QOS = "qos" CONF_SET_POSITION_TEMPLATE = "set_position_template" CONF_USE_FAHRENHEIT = "use_fahrenheit" CONF_USE_KWH = "use_kwh" DEFAULT_DISC_PREFIX = "homeassistant" DEVICE_CLASS_AWNING = "awning" DEVICE_CLASS_BATTERY = "battery" DEVICE_CLASS_BATTERY_CHARGING = "battery_charging" DEVICE_CLASS_BLIND = "blind" DEVICE_CLASS_COLD = "cold" DEVICE_CLASS_CONNECTIVITY = "connectivity" DEVICE_CLASS_CURRENT = "current" DEVICE_CLASS_CURTAIN = "curtain" DEVICE_CLASS_DAMPER = "damper" DEVICE_CLASS_DOOR = "door" DEVICE_CLASS_ENERGY = "energy" DEVICE_CLASS_GARAGE = "garage" DEVICE_CLASS_GARAGE_DOOR = "garage_door" DEVICE_CLASS_GAS = "gas" DEVICE_CLASS_GATE = "gate" DEVICE_CLASS_HEAT = "heat" DEVICE_CLASS_HUMIDITY = "humidity" DEVICE_CLASS_ILLUMINANCE = "illuminance" DEVICE_CLASS_LIGHT = "light" DEVICE_CLASS_LOCK = "lock" DEVICE_CLASS_MOISTURE = "moisture" DEVICE_CLASS_MOTION = "motion" DEVICE_CLASS_MOVING = "moving" DEVICE_CLASS_OCCUPANCY = "occupancy" DEVICE_CLASS_OPENING = "opening" DEVICE_CLASS_PLUG = "plug" DEVICE_CLASS_POWER = "power" DEVICE_CLASS_POWER_FACTOR = "power_factor" DEVICE_CLASS_PRESENCE = "presence" DEVICE_CLASS_PRESSURE = "pressure" DEVICE_CLASS_PROBLEM = "problem" DEVICE_CLASS_RESTART = "restart" DEVICE_CLASS_SAFETY = "safety" DEVICE_CLASS_SHADE = "shade" DEVICE_CLASS_SHUTTER = "shutter" DEVICE_CLASS_SIGNAL_STRENGTH = "signal_strength" DEVICE_CLASS_SMOKE = "smoke" DEVICE_CLASS_SOUND = "sound" DEVICE_CLASS_TEMPERATURE = "temperature" DEVICE_CLASS_TIMESTAMP = "timestamp" DEVICE_CLASS_UPDATE = "update" DEVICE_CLASS_VIBRATION = "vibration" DEVICE_CLASS_VOLTAGE = "voltage" DEVICE_CLASS_WINDOW = "window" ENTITY_CATEGORY_CONFIG = "config" ENTITY_CATEGORY_DIAGNOSTIC = "diagnostic" EXPIRE_AFTER_FOR_BATTERY_POWERED = int(1.2 * 12 * 60 * 60) # 1.2 * 12 h EXPIRE_AFTER_FOR_AC_POWERED = int(2.2 * 10 * 60) # 2.2 * 10 min EXPIRE_AFTER_FOR_SHELLY_MOTION = int(1.2 * 60 * 60) # 1.2 * 60 min EXPIRE_AFTER_FOR_SHELLY_VALVE = int(1.2 * 60 * 60) # 1.2 * 60 min KEY_ACTION_TEMPLATE = "act_tpl" KEY_ACTION_TOPIC = "act_t" KEY_AUTOMATION_TYPE = "atype" KEY_AVAILABILITY_TOPIC = "avty_t" KEY_BRIGHTNESS_TEMPLATE = "bri_tpl" KEY_COLOR_TEMP_TEMPLATE = "clr_temp_tpl" KEY_COMMAND_OFF_TEMPLATE = "cmd_off_tpl" KEY_COMMAND_ON_TEMPLATE = "cmd_on_tpl" KEY_COMMAND_TEMPLATE = "cmd_tpl" KEY_COMMAND_TOPIC = "cmd_t" KEY_CONFIGURATION_URL = "cu" KEY_CONNECTIONS = "cns" KEY_CURRENT_TEMPERATURE_TEMPLATE = "curr_temp_tpl" KEY_CURRENT_TEMPERATURE_TOPIC = "curr_temp_t" KEY_DEVICE = "dev" KEY_DEVICE_CLASS = "dev_cla" KEY_ENABLED_BY_DEFAULT = "en" KEY_ENTITY_CATEGORY = "entity_category" KEY_EXPIRE_AFTER = "exp_aft" KEY_FORCE_UPDATE = "frc_upd" KEY_HW_VERSION = "hw" KEY_ICON = "icon" KEY_JSON_ATTRIBUTES_TEMPLATE = "json_attr_tpl" KEY_JSON_ATTRIBUTES_TOPIC = "json_attr_t" KEY_MAC = "mac" KEY_MANUFACTURER = "mf" KEY_MAX = "max" KEY_MAX_MIREDS = "max_mirs" KEY_MAX_TEMP = "max_temp" KEY_MIN = "min" KEY_MIN_MIREDS = "min_mirs" KEY_MIN_TEMP = "min_temp" KEY_MODE_STATE_TEMPLATE = "mode_stat_tpl" KEY_MODE_STATE_TOPIC = "mode_stat_t" KEY_MODEL = "mdl" KEY_MODES = "modes" KEY_NAME = "name" KEY_OFF_DELAY = "off_dly" KEY_OPTIMISTIC = "opt" KEY_OPTIONS = "options" KEY_PAYLOAD = "pl" KEY_PAYLOAD_AVAILABLE = "pl_avail" KEY_PAYLOAD_CLOSE = "pl_cls" KEY_PAYLOAD_NOT_AVAILABLE = "pl_not_avail" KEY_PAYLOAD_OFF = "pl_off" KEY_PAYLOAD_ON = "pl_on" KEY_PAYLOAD_OPEN = "pl_open" KEY_PAYLOAD_PRESS = "payload_press" KEY_PAYLOAD_STOP = "pl_stop" KEY_POSITION_TEMPLATE = "pos_tpl" KEY_POSITION_TOPIC = "pos_t" KEY_PRECISION = "precision" KEY_QOS = "qos" KEY_RETAIN = "ret" KEY_SCHEMA = "schema" KEY_SET_POSITION_TEMPLATE = "set_pos_tpl" KEY_SET_POSITION_TOPIC = "set_pos_t" KEY_STATE_CLASS = "stat_cla" KEY_STATE_CLOSING = "stat_closing" KEY_STATE_OFF = "stat_off" KEY_STATE_ON = "stat_on" KEY_STATE_OPENING = "stat_opening" KEY_STATE_STOPPED = "stat_stopped" KEY_STATE_TEMPLATE = "stat_tpl" KEY_STATE_TOPIC = "stat_t" KEY_STEP = "step" KEY_SUBTYPE = "stype" KEY_SW_VERSION = "sw" KEY_TEMP_STEP = "temp_step" KEY_TEMPERATURE_COMMAND_TEMPLATE = "temp_cmd_tpl" KEY_TEMPERATURE_COMMAND_TOPIC = "temp_cmd_t" KEY_TEMPERATURE_STATE_TEMPLATE = "temp_stat_tpl" KEY_TEMPERATURE_STATE_TOPIC = "temp_stat_t" KEY_TOPIC = "t" KEY_TYPE = "type" KEY_UNIQUE_ID = "uniq_id" KEY_UNIT = "unit_of_meas" KEY_VALUE_TEMPLATE = "val_tpl" LIGHT_COLOR = "color" LIGHT_WHITE = "white" # Maximum light transition time in milliseconds MAX_TRANSITION = 5000 # Firmware 1.6.5 release date MIN_4PRO_FIRMWARE_DATE = 20200408 # Firmware 1.9.4 release date MIN_PLUG_FIRMWARE_DATE = 20210115 # Firmware 1.1.0 release date MIN_MOTION_FIRMWARE_DATE = 20220517 # Firmware 2.1.4-rc1 release date MIN_MOTION2_FIRMWARE_DATE = 20220301 # Firmware 2.1.5 release date MIN_VALVE_FIRMWARE_DATE = 20220404 # Firmware 1.11.7 release date MIN_DIMMER_FIRMWARE_DATE = 20211109 # Firmware 1.11.7 release date MIN_HT_FIRMWARE_DATE = 20211109 # Firmware 1.11.8 release date MIN_FIRMWARE_DATE = 20220209 MODEL_SHELLY1 = f"{ATTR_SHELLY} 1" MODEL_SHELLY1L = f"{ATTR_SHELLY} 1L" MODEL_SHELLY1PM = f"{ATTR_SHELLY} 1PM" MODEL_SHELLY2 = f"{ATTR_SHELLY} 2" MODEL_SHELLY25 = f"{ATTR_SHELLY} 2.5" MODEL_SHELLY3EM = f"{ATTR_SHELLY} 3EM" MODEL_SHELLY4PRO = f"{ATTR_SHELLY} 4Pro" MODEL_SHELLYAIR = f"{ATTR_SHELLY} Air" MODEL_SHELLYBULB = f"{ATTR_SHELLY} Bulb" MODEL_SHELLYBULBRGBW = f"{ATTR_SHELLY} DUO RGBW" MODEL_SHELLYBUTTON1 = f"{ATTR_SHELLY} Button1" MODEL_SHELLYDIMMER = f"{ATTR_SHELLY} Dimmer" MODEL_SHELLYDIMMER2 = f"{ATTR_SHELLY} Dimmer 2" MODEL_SHELLYDUO = f"{ATTR_SHELLY} DUO" MODEL_SHELLYDW = f"{ATTR_SHELLY} Door/Window" MODEL_SHELLYDW2 = f"{ATTR_SHELLY} Door/Window 2" MODEL_SHELLYEM = f"{ATTR_SHELLY} EM" MODEL_SHELLYFLOOD = f"{ATTR_SHELLY} Flood" MODEL_SHELLYGAS = f"{ATTR_SHELLY} Gas" MODEL_SHELLYHT = f"{ATTR_SHELLY} H&T" MODEL_SHELLYI3 = f"{ATTR_SHELLY} i3" MODEL_SHELLYMOTION = f"{ATTR_SHELLY} Motion" MODEL_SHELLYMOTION2 = f"{ATTR_SHELLY} Motion 2" MODEL_SHELLYPLUG = f"{ATTR_SHELLY} Plug" MODEL_SHELLYPLUG_S = f"{ATTR_SHELLY} Plug S" MODEL_SHELLYPLUG_US = f"{ATTR_SHELLY} Plug US" MODEL_SHELLYRGBW2 = f"{ATTR_SHELLY} RGBW2" MODEL_SHELLYSENSE = f"{ATTR_SHELLY} Sense" MODEL_SHELLYSMOKE = f"{ATTR_SHELLY} Smoke" MODEL_SHELLYUNI = f"{ATTR_SHELLY} UNI" MODEL_SHELLYVALVE = f"{ATTR_SHELLY} Valve" MODEL_SHELLYVINTAGE = f"{ATTR_SHELLY} Vintage" MODEL_SHELLY1_ID = "SHSW-1" # Shelly 1 MODEL_SHELLY1_PREFIX = "shelly1" MODEL_SHELLY1L_ID = "SHSW-L" # Shelly 1L MODEL_SHELLY1L_PREFIX = "shelly1l" MODEL_SHELLY1PM_ID = "SHSW-PM" # Shelly 1PM MODEL_SHELLY1PM_PREFIX = "shelly1pm" MODEL_SHELLY2_ID = "SHSW-21" # Shelly 2 MODEL_SHELLY2_PREFIX = "shellyswitch" MODEL_SHELLY25_ID = "SHSW-25" # Shelly 2.5 MODEL_SHELLY25_PREFIX = "shellyswitch25" MODEL_SHELLY3EM_ID = "SHEM-3" # Shelly 3EM MODEL_SHELLY3EM_PREFIX = "shellyem3" MODEL_SHELLY4PRO_ID = "SHSW-44" # Shelly 4Pro MODEL_SHELLY4PRO_PREFIX = "shelly4pro" MODEL_SHELLYAIR_ID = "SHAIR-1" # Shelly Air MODEL_SHELLYAIR_PREFIX = "shellyair" MODEL_SHELLYBULB_ID = "SHBLB-1" # Shelly Bulb MODEL_SHELLYBULB_PREFIX = "shellybulb" MODEL_SHELLYBULBRGBW_ID = "SHCB-1" # Shelly DUO RGBW MODEL_SHELLYBULBRGBW_PREFIX = "shellycolorbulb" MODEL_SHELLYBUTTON1_ID = "SHBTN-1" # Shelly Button1 MODEL_SHELLYBUTTON1V2_ID = "SHBTN-2" # Shelly Button1 v2 MODEL_SHELLYBUTTON1_PREFIX = "shellybutton1" MODEL_SHELLYDIMMER_ID = "SHDM-1" # Shelly Dimmer MODEL_SHELLYDIMMER_PREFIX = "shellydimmer" MODEL_SHELLYDIMMER2_ID = "SHDM-2" # Shelly Dimmer 2 MODEL_SHELLYDIMMER2_PREFIX = "shellydimmer2" MODEL_SHELLYDUO_ID = "SHBDUO-1" # Shelly Duo MODEL_SHELLYDUO_PREFIX = "shellybulbduo" MODEL_SHELLYDW_ID = "SHDW-1" # Shelly Door/Window MODEL_SHELLYDW_PREFIX = "shellydw" MODEL_SHELLYDW2_ID = "SHDW-2" # Shelly Door/Window 2 MODEL_SHELLYDW2_PREFIX = "shellydw2" MODEL_SHELLYEM_ID = "SHEM" # Shelly EM MODEL_SHELLYEM_PREFIX = "shellyem" MODEL_SHELLYFLOOD_ID = "SHWT-1" # Shelly Flood MODEL_SHELLYFLOOD_PREFIX = "shellyflood" MODEL_SHELLYGAS_ID = "SHGS-1" # Shelly Gas MODEL_SHELLYGAS_PREFIX = "shellygas" MODEL_SHELLYHT_ID = "SHHT-1" # Shelly H&T MODEL_SHELLYHT_PREFIX = "shellyht" MODEL_SHELLYI3_ID = "SHIX3-1" # Shelly i3 MODEL_SHELLYI3_PREFIX = "shellyix3" MODEL_SHELLYMOTION_ID = "SHMOS-01" # Shelly Motion MODEL_SHELLYMOTION_PREFIX = "shellymotionsensor" MODEL_SHELLYMOTION2_ID = "SHMOS-02" # Shelly Motion MODEL_SHELLYMOTION2_PREFIX = "shellymotionsensor2" MODEL_SHELLYPLUG_ID = "SHPLG-1" # Shelly Plug MODEL_SHELLYPLUG_E_ID = "SHPLG2-1" # Shelly Plug E MODEL_SHELLYPLUG_PREFIX = "shellyplug" MODEL_SHELLYPLUG_S_ID = "SHPLG-S" # Shelly Plug S MODEL_SHELLYPLUG_S_PREFIX = "shellyplug-s" MODEL_SHELLYPLUG_US_ID = "SHPLG-U1" # Shelly Plug US MODEL_SHELLYPLUG_US_PREFIX = "shellyplug-u1" MODEL_SHELLYRGBW2_ID = "SHRGBW2" # Shelly RGBW2 MODEL_SHELLYRGBW2_PREFIX = "shellyrgbw2" MODEL_SHELLYSENSE_ID = "SHSEN-1" # Shelly Sense MODEL_SHELLYSENSE_PREFIX = "shellysense" MODEL_SHELLYSMOKE_ID = "SHSM-01" # Shelly Smoke MODEL_SHELLYSMOKE_PREFIX = "shellysmoke" MODEL_SHELLYVALVE_ID = "SHTRV-01" # Shelly Valve MODEL_SHELLYVALVE_PREFIX = "shellytrv" MODEL_SHELLYVINTAGE_ID = "SHVIN-1" # Shelly Vintage MODEL_SHELLYVINTAGE_PREFIX = "shellyvintage" MODEL_SHELLYUNI_ID = "SHUNI-1" # Shelly UNI MODEL_SHELLYUNI_PREFIX = "shellyuni" NUMBER_BOOST_TIME = "boost_time" NUMBER_MINIMAL_VALVE_POSITION = "minimal_valve_position" NUMBER_VALVE_POSITION = "valve_position" OFF_DELAY = 1 PL_CLOSE = "close" PL_MUTE = "mute" PL_OPEN = "open" PL_RESTART = "reboot" PL_SELF_TEST = "self_test" PL_UNMUTE = "unmute" PL_UPDATE_FIRMWARE = "update_fw" SELECT_PROFILES = "profiles" SENSOR_ADC = "adc" SENSOR_BATTERY = "battery" SENSOR_CALIBRATED = "calibrated" SENSOR_CHARGER = "charger" SENSOR_CLOUD = "cloud" SENSOR_CONCENTRATION = "concentration" SENSOR_CURRENT = "current" SENSOR_DOUBLE_SHORTPUSH = "double shortpush" SENSOR_DOUBLE_SHORTPUSH_0 = "double shortpush 0" SENSOR_DOUBLE_SHORTPUSH_1 = "double shortpush 1" SENSOR_DOUBLE_SHORTPUSH_2 = "double shortpush 2" SENSOR_ENERGY = "energy" SENSOR_EXT_HUMIDITY = "ext_humidity" SENSOR_EXT_SWITCH = "ext_switch" SENSOR_EXT_TEMPERATURE = "ext_temperature" SENSOR_FIRMWARE_UPDATE = "firmware update" SENSOR_FLOOD = "flood" SENSOR_GAS = "gas" SENSOR_HUMIDITY = "humidity" SENSOR_ILLUMINATION = "illumination" SENSOR_INPUT = "input" SENSOR_INPUT_0 = "input 0" SENSOR_INPUT_1 = "input 1" SENSOR_INPUT_2 = "input 2" SENSOR_IP = "ip" SENSOR_LAST_RESTART = "last_restart" SENSOR_LOADERROR = "loaderror" SENSOR_LONGPUSH = "longpush" SENSOR_LONGPUSH_0 = "longpush 0" SENSOR_LONGPUSH_1 = "longpush 1" SENSOR_LONGPUSH_2 = "longpush 2" SENSOR_LONGPUSH_SHORTPUSH_0 = "longpush shortpush 0" SENSOR_LONGPUSH_SHORTPUSH_1 = "longpush shortpush 1" SENSOR_LONGPUSH_SHORTPUSH_2 = "longpush shortpush 2" SENSOR_LUX = "lux" SENSOR_MOTION = "motion" SENSOR_OPENING = "opening" SENSOR_OPERATION = "operation" SENSOR_OVERLOAD = "overload" SENSOR_OVERPOWER = "overpower" SENSOR_OVERPOWER_VALUE = "overpower_value" SENSOR_OVERTEMPERATURE = "overtemperature" SENSOR_POWER = "power" SENSOR_POWER_FACTOR = "pf" SENSOR_REACTIVE_POWER = "reactive_power" SENSOR_RETURNED_ENERGY = "returned_energy" SENSOR_RSSI = "rssi" SENSOR_SELF_TEST = "self_test" SENSOR_SHORTPUSH = "shortpush" SENSOR_SHORTPUSH_0 = "shortpush/0" SENSOR_SHORTPUSH_1 = "shortpush/1" SENSOR_SHORTPUSH_2 = "shortpush/2" SENSOR_SHORTPUSH_LONGPUSH_0 = "shortpush longpush 0" SENSOR_SHORTPUSH_LONGPUSH_1 = "shortpush longpush 1" SENSOR_SHORTPUSH_LONGPUSH_2 = "shortpush longpush 2" SENSOR_SMOKE = "smoke" SENSOR_SSID = "ssid" SENSOR_TEMPERATURE = "temperature" SENSOR_TEMPERATURE_F = "temperature_f" SENSOR_TEMPERATURE_STATUS = "temperature_status" SENSOR_TILT = "tilt" SENSOR_TOTAL = "total" SENSOR_TOTAL_RETURNED = "total_returned" SENSOR_TOTALWORKTIME = "totalworktime" SENSOR_TRIPLE_SHORTPUSH = "triple shortpush" SENSOR_TRIPLE_SHORTPUSH_0 = "triple shortpush 0" SENSOR_TRIPLE_SHORTPUSH_1 = "triple shortpush 1" SENSOR_TRIPLE_SHORTPUSH_2 = "triple shortpush 2" SENSOR_UPTIME = "uptime" SENSOR_VALVE = "valve" SENSOR_VIBRATION = "vibration" SENSOR_VOLTAGE = "voltage" STATE_CLASS_MEASUREMENT = "measurement" STATE_CLASS_TOTAL_INCREASING = "total_increasing" SWITCH_ACCELERATED_HEATING = "accelerated_heating" SWITCH_SCHEDULE = "schedule" TOPIC_ADC = "~adc/0" TOPIC_ANNOUNCE = "~announce" TOPIC_CHARGER = "~charger" TOPIC_COLOR_0_STATUS = "~color/0/status" TOPIC_COMMAND = "~command" TOPIC_COMMAND_ACCELERATED_HEATING = "~thermostat/0/command/accelerated_heating" TOPIC_COMMAND_BOOST_MINUTES = "~thermostat/0/command/boost_minutes" TOPIC_COMMAND_PROFILES = "~thermostat/0/command/schedule_profile" TOPIC_COMMAND_SCHEDULE = "~thermostat/0/command/schedule" TOPIC_COMMAND_VALVE_MIN = "~thermostat/0/command/valve_min_percent" TOPIC_COMMAND_VALVE_POSITION = "~thermostat/0/command/valve_pos" TOPIC_ENERGY = "~relay/energy" TOPIC_EXT_SWITCH = "~ext_switch/0" TOPIC_INFO = "~info" TOPIC_INPUT_0 = "~input/0" TOPIC_INPUT_1 = "~input/1" TOPIC_INPUT_2 = "~input/2" TOPIC_INPUT_EVENT = "~input_event" TOPIC_INPUT_EVENT_0 = "~input_event/0" TOPIC_INPUT_EVENT_1 = "~input_event/1" TOPIC_INPUT_EVENT_2 = "~input_event/2" TOPIC_LIGHT_ENERGY = "~light/{light_id}/energy" TOPIC_LIGHT_ENERGY_RGBW2_COLOR = "~color/{light_id}/energy" TOPIC_LIGHT_ENERGY_RGBW2_WHITE = "~white/{light_id}/energy" TOPIC_LIGHT_OVERPOWER_VALUE = "~light/{light_id}/overpower_value" TOPIC_LIGHT_POWER = "~light/{light_id}/power" TOPIC_LIGHT_POWER_RGBW2_COLOR = "~color/{light_id}/power" TOPIC_LIGHT_POWER_RGBW2_WHITE = "~white/{light_id}/power" TOPIC_LIGHT_SET = "~light/{light_id}/set" TOPIC_LIGHT_STATUS = "~light/{light_id}/status" TOPIC_LOADERROR = "~loaderror" TOPIC_METER_CURRENT = "~emeter/{meter_id}/current" TOPIC_METER_ENERGY = "~emeter/{meter_id}/energy" TOPIC_METER_POWER = "~emeter/{meter_id}/power" TOPIC_METER_POWER_FACTOR = "~emeter/{meter_id}/pf" TOPIC_METER_REACTIVE_POWER = "~emeter/{meter_id}/reactive_power" TOPIC_METER_RETURNED_ENERGY = "~emeter/{meter_id}/returned_energy" TOPIC_METER_TOTAL = "~emeter/{meter_id}/total" TOPIC_METER_TOTAL_RETURNED = "~emeter/{meter_id}/total_returned" TOPIC_METER_VOLTAGE = "~emeter/{meter_id}/voltage" TOPIC_MUTE = "~sensor/mute" TOPIC_ONLINE = "~online" TOPIC_OVERLOAD = "~overload" TOPIC_OVERPOWER_VALUE = "overpower_value" TOPIC_OVERTEMPERATURE = "~overtemperature" TOPIC_POWER = "~relay/power" TOPIC_RELAY = "~relay" TOPIC_RELAY_ENERGY = "~relay/{relay_id}/energy" TOPIC_RELAY_POWER = "~relay/{relay_id}/power" TOPIC_ROLLER_ENERGY = "~roller/0/energy" TOPIC_ROLLER_POWER = "~roller/0/power" TOPIC_SELF_TEST = "~sensor/start_self_test" TOPIC_SENSOR_BATTERY = "~sensor/battery" TOPIC_SENSOR_CHARGER = "~sensor/charger" TOPIC_SENSOR_CONCENTRATION = "~sensor/concentration" TOPIC_SENSOR_GAS = "~sensor/gas" TOPIC_SENSOR_HUMIDITY = "~sensor/humidity" TOPIC_SENSOR_LUX = "~sensor/lux" TOPIC_SENSOR_OPERATION = "~sensor/operation" TOPIC_SENSOR_SELF_TEST = "~sensor/self_test" TOPIC_SENSOR_SMOKE = "~sensor/smoke" TOPIC_SENSOR_STATE = "~sensor/state" TOPIC_SENSOR_FLOOD = "~sensor/flood" TOPIC_SENSOR_TEMPERATURE = "~sensor/temperature" TOPIC_SENSOR_TILT = "~sensor/tilt" TOPIC_SENSOR_UNMUTE = "~sensor/unmute" TOPIC_SENSOR_VIBRATION = "~sensor/vibration" TOPIC_SETTINGS = "~settings" TOPIC_STATUS = "~status" TOPIC_TEMPERATURE = "~temperature" TOPIC_TEMPERATURE_STATUS = "~temperature_status" TOPIC_TOTAL_WORK_TIME = "~totalworktime" TOPIC_VALVE = "~valve/0/state" TOPIC_VALVE_COMMAND = "~valve/0/command" TOPIC_VOLTAGE = "~voltage" TOPIC_WHITE_SET = "~white/{light_id}/set" TOPIC_WHITE_STATUS = "~white/{light_id}/status" TPL_ACCELERATED_HEATING = "{{value_json.thermostats.0.target_t.accelerated_heating}}" TPL_ACTION_TEMPLATE = "{{%if value_json.thermostats.0.target_t.value<={min_temp}%}}off{{%elif value_json.thermostats.0.pos==0%}}idle{{%else%}}heating{{%endif%}}" TPL_ADC = "{{value|float|round(2)}}" TPL_BATTERY = "{{value|float|round}}" TPL_BATTERY_FROM_INFO = "{{value_json.bat.value}}" TPL_BATTERY_FROM_JSON = "{{value_json.bat}}" TPL_BOOST_MINUTES = "{{value_json.thermostats.0.boost_minutes}}" TPL_CALIBRATED = "{%if value_json.calibrated==true%}ON{%else%}OFF{%endif%}" TPL_CHARGER = "{%if value_json.charger==true%}ON{%else%}OFF{%endif%}" TPL_CLOUD = "{%if value_json.cloud.connected==true%}ON{%else%}OFF{%endif%}" TPL_COLOR_TEMP_WHITE_LIGHT = ( "{{((1000000/(value_json.temp|int,2700)|max)|round(0,^floor^))}}" ) TPL_COMMAND_ON_WHITE_LIGHT = "{{^turn^:^on^{{%if brightness is defined%}},^brightness^:{{{{brightness|float|multiply(0.3922)|round}}}}{{%endif%}}{{%if transition is defined%}},^transition^:{{{{min(transition|multiply(1000), {max_transition})}}}}{{%endif%}}}}" TPL_COMMAND_ON_WHITE_LIGHT_DUO = "{{^turn^:^on^{{%if brightness is defined%}},^brightness^:{{{{brightness|float|multiply(0.3922)|round}}}}{{%endif%}}{{%if color_temp is defined%}},^temp^:{{{{(1000000/(color_temp|int))|round(0,^floor^)}}}}{{%endif%}}{{%if transition is defined%}},^transition^:{{{{min(transition|multiply(1000), {max_transition})}}}}{{%endif%}}}}" TPL_COMMAND_PROFILES = "{{value.split(^ ^)[-1]}}" TPL_CONCENTRATION = ( "{%if is_number(value) and 0<=value|int<=65535%}{{value}}{%else%}unknown{%endif%}" ) TPL_CURRENT = "{{value|float|round(2)}}" TPL_CURRENT_TEMPERATURE = "{{value_json.thermostats.0.tmp.value}}" TPL_DOUBLE_SHORTPUSH = "{%if value_json.event==^SS^%}ON{%else%}OFF{%endif%}" TPL_ENERGY_WH = "{{value|float|round(2)}}" TPL_ENERGY_WH_KWH = "{{(value|float/1000)|round(2)}}" TPL_ENERGY_WMIN = "{{(value|float/60)|round(2)}}" TPL_ENERGY_WMIN_KWH = "{{(value|float/60/1000)|round(2)}}" TPL_GAS = "{%if value in [^mild^,^heavy^]%}ON{%else%}OFF{%endif%}" TPL_GAS_TO_JSON = "{{{^status^:value}|tojson}}" TPL_HUMIDITY = "{%if is_number(value) and 0 0: result[0] except TypeError: logger.error("Wrong configuration for %s", dev_id) # noqa: F821 result = {} finally: return result def mqtt_publish(topic, payload, retain, json=False): """Publish data to MQTT broker.""" if json: payload_str = str(payload).replace("'", '"').replace("^", '\\"') else: payload_str = str(payload).replace("'", '"').replace("^", "'") service_data = { "topic": topic, "payload": payload_str, "retain": retain, "qos": 0, } logger.debug(service_data) # noqa: F821 logger.debug("Sending to MQTT broker: %s %s", topic, payload_str) # noqa: F821 hass.services.call("mqtt", "publish", service_data, False) # noqa: F821 expire_after = None qos = 0 retain = True no_battery_sensor = False fw_ver = data.get(CONF_FW_VER) # noqa: F821 dev_id = data.get(CONF_ID) # noqa: F821 model_id = data.get(CONF_MODEL_ID) # noqa: F821 mode = data.get(CONF_MODE) # noqa: F821 host = data.get(CONF_HOST) # noqa: F821 if not host: raise ValueError( "host value None is not valid, update shellies_discovery automation" ) use_fahrenheit = False roller_mode = False if mode == "roller": roller_mode = True ignored = [ element.lower() for element in data.get(CONF_IGNORED_DEVICES, []) # noqa: F821 ] # noqa: F821 mac = data.get(CONF_MAC) # noqa: F821 if not dev_id: raise ValueError("id value None is not valid, check script configuration") if "^" in dev_id: raise ValueError("Wrong char ^ in id, change device configuration") if len(dev_id) > 32: raise ValueError( f"id value {dev_id} is longer than 32 characters, use shorter custom MQTT prefix" ) if not mac: raise ValueError("mac value None is not valid, check script configuration") if not fw_ver: raise ValueError("fw_ver value None is not valid, check script configuration") mac = str(mac).lower() dev_id_prefix = dev_id.rsplit("-", 1)[0].lower() # compatibility with old firmware if dev_id_prefix == MODEL_SHELLY4PRO_PREFIX: model_id = MODEL_SHELLY4PRO_ID if not model_id: raise ValueError("model_id value None is not valid, check script configuration") try: cur_ver_date = parse_version(fw_ver) except (IndexError, ValueError): raise ValueError( f"Firmware version {fw_ver} is not supported, update your device {dev_id}" ) min_ver_date = DEVICE_FIRMWARE_MAP[model_id] if cur_ver_date < min_ver_date: raise ValueError( f"Firmware dated {min_ver_date} is required, update your device {dev_id}" ) logger.debug( # noqa: F821 "id: %s, mac: %s, fw_ver: %s, model: %s", dev_id, mac, fw_ver, model_id ) try: if int(data.get(CONF_QOS, 0)) in (0, 1, 2): # noqa: F821 qos = int(data.get(CONF_QOS, 0)) # noqa: F821 else: raise ValueError() except ValueError: logger.error("Not valid qos value, the default value 0 was used") # noqa: F821 optimistic = data.get(CONF_OPTIMISTIC, False) # noqa: F821 if not isinstance(optimistic, bool): optimistic = False disc_prefix = data.get(CONF_DISCOVERY_PREFIX, DEFAULT_DISC_PREFIX) # noqa: F821 ignore_device_model = data.get(CONF_IGNORE_DEVICE_MODEL, False) # noqa: F821 if not isinstance(ignore_device_model, bool): ignore_device_model = False develop = data.get(CONF_DEVELOP, False) # noqa: F821 if develop: disc_prefix = "develop" retain = False logger.error("DEVELOP MODE !!!") # noqa: F821 battery_powered = False buttons = {} climate_entity_option = {} ext_humi_sensors = 0 ext_temp_sensors = 0 inputs = 0 inputs_types = [] lights_bin_sensors = [] lights_bin_sensors_device_classes = [] lights_bin_sensors_pl = [] lights_bin_sensors_tpls = [] meters = 0 meter_sensors = {} model = None relay_components = [COMP_SWITCH, COMP_LIGHT, COMP_FAN] relays = 0 relays_bin_sensors = [] relays_bin_sensors_device_classes = [] relays_bin_sensors_entity_categories = [] relays_bin_sensors_pl = [] relays_bin_sensors_topics = [] relays_bin_sensors_tpls = [] relay_sensors = {} light_sensors = {} rgbw_lights = 0 rollers = 0 binary_sensors = {} numbers = {} selectors = {} sensors = {} switches = {} white_lights = {} if model_id == MODEL_SHELLY1_ID or dev_id_prefix == MODEL_SHELLY1_PREFIX: model = MODEL_SHELLY1 ext_humi_sensors = 1 ext_temp_sensors = 3 inputs = 1 relays = 1 binary_sensors = { SENSOR_EXT_SWITCH: OPTIONS_SENSOR_EXT_SWITCH, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] relays_bin_sensors = [ SENSOR_INPUT, SENSOR_LONGPUSH, SENSOR_SHORTPUSH, ] relays_bin_sensors_entity_categories = [None, None, None] relays_bin_sensors_device_classes = [None, None, None] relays_bin_sensors_pl = [PL_1_0, None, None] relays_bin_sensors_topics = [None, TOPIC_INPUT_EVENT, TOPIC_INPUT_EVENT] relays_bin_sensors_tpls = [None, TPL_LONGPUSH, TPL_SHORTPUSH] sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLY1L_ID or dev_id_prefix == MODEL_SHELLY1L_PREFIX: model = MODEL_SHELLY1L ext_humi_sensors = 1 ext_temp_sensors = 3 inputs = 2 relays = 1 binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_INPUT_1: OPTIONS_SENSOR_INPUT_1, SENSOR_LONGPUSH_0: OPTIONS_SENSOR_LONGPUSH_0, SENSOR_LONGPUSH_1: OPTIONS_SENSOR_LONGPUSH_1, SENSOR_OVERTEMPERATURE: OPTIONS_SENSOR_OVERTEMPERATURE, SENSOR_SHORTPUSH_0: OPTIONS_SENSOR_SHORTPUSH_0, SENSOR_SHORTPUSH_1: OPTIONS_SENSOR_SHORTPUSH_1, } inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_TEMPERATURE: OPTIONS_SENSOR_DEVICE_TEMPERATURE, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLY1PM_ID or dev_id_prefix == MODEL_SHELLY1PM_PREFIX: model = MODEL_SHELLY1PM relays = 1 inputs = 1 ext_humi_sensors = 1 ext_temp_sensors = 3 inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } relays_bin_sensors = [ SENSOR_INPUT, SENSOR_LONGPUSH, SENSOR_SHORTPUSH, SENSOR_OVERPOWER, ] relays_bin_sensors_entity_categories = [ None, None, None, ENTITY_CATEGORY_DIAGNOSTIC, ] relays_bin_sensors_pl = [PL_1_0, None, None, None] relays_bin_sensors_topics = [ None, TOPIC_INPUT_EVENT, TOPIC_INPUT_EVENT, TOPIC_RELAY, ] relays_bin_sensors_tpls = [None, TPL_LONGPUSH, TPL_SHORTPUSH, TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [None, None, None, DEVICE_CLASS_PROBLEM] sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_TEMPERATURE: OPTIONS_SENSOR_DEVICE_TEMPERATURE, SENSOR_TEMPERATURE_STATUS: OPTIONS_SENSOR_TEMPERATURE_STATUS, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_OVERTEMPERATURE: OPTIONS_SENSOR_OVERTEMPERATURE, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYAIR_ID or dev_id_prefix == MODEL_SHELLYAIR_PREFIX: model = MODEL_SHELLYAIR relays = 1 relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } relays_bin_sensors = [SENSOR_INPUT] relays_bin_sensors_entity_categories = [None] relays_bin_sensors_pl = [PL_1_0] relays_bin_sensors_tpls = [None] relays_bin_sensors_device_classes = [None] sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_TEMPERATURE: OPTIONS_SENSOR_DEVICE_TEMPERATURE, SENSOR_TOTALWORKTIME: OPTIONS_SENSOR_TOTALWORKTIME, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_OVERTEMPERATURE: OPTIONS_SENSOR_OVERTEMPERATURE, } ext_temp_sensors = 1 buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLY2_ID or dev_id_prefix == MODEL_SHELLY2_PREFIX: model = MODEL_SHELLY2 relays = 2 rollers = 1 inputs = 2 inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] relays_bin_sensors = [ SENSOR_LONGPUSH, SENSOR_SHORTPUSH, SENSOR_OVERPOWER, ] relays_bin_sensors_entity_categories = [None, None, ENTITY_CATEGORY_DIAGNOSTIC] relays_bin_sensors_pl = [None, None, None] relays_bin_sensors_topics = [TOPIC_INPUT_EVENT, TOPIC_INPUT_EVENT, TOPIC_RELAY] relays_bin_sensors_tpls = [TPL_LONGPUSH, TPL_SHORTPUSH, TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [None, None, DEVICE_CLASS_PROBLEM] binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_INPUT_1: OPTIONS_SENSOR_INPUT_1, } sensors = { SENSOR_ENERGY: OPTIONS_SENSOR_ENERGY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_POWER: OPTIONS_SENSOR_POWER, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_VOLTAGE: OPTIONS_SENSOR_VOLTAGE, } if roller_mode: sensors[SENSOR_ENERGY] = OPTIONS_SENSOR_ROLLER_ENERGY sensors[SENSOR_POWER] = OPTIONS_SENSOR_ROLLER_POWER else: sensors[SENSOR_ENERGY] = OPTIONS_SENSOR_ENERGY sensors[SENSOR_POWER] = OPTIONS_SENSOR_POWER buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLY25_ID or dev_id_prefix == MODEL_SHELLY25_PREFIX: model = MODEL_SHELLY25 relays = 2 rollers = 1 inputs = 2 inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } relays_bin_sensors = [ SENSOR_LONGPUSH, SENSOR_SHORTPUSH, SENSOR_OVERPOWER, ] relays_bin_sensors_entity_categories = [None, None, ENTITY_CATEGORY_DIAGNOSTIC] relays_bin_sensors_pl = [None, None, None] relays_bin_sensors_topics = [TOPIC_INPUT_EVENT, TOPIC_INPUT_EVENT, TOPIC_RELAY] relays_bin_sensors_tpls = [TPL_LONGPUSH, TPL_SHORTPUSH, TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [None, None, DEVICE_CLASS_PROBLEM] sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_TEMPERATURE: OPTIONS_SENSOR_DEVICE_TEMPERATURE, SENSOR_TEMPERATURE_STATUS: OPTIONS_SENSOR_TEMPERATURE_STATUS, SENSOR_VOLTAGE: OPTIONS_SENSOR_VOLTAGE, SENSOR_ENERGY: OPTIONS_SENSOR_ROLLER_ENERGY, SENSOR_POWER: OPTIONS_SENSOR_ROLLER_POWER, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_INPUT_1: OPTIONS_SENSOR_INPUT_1, SENSOR_OVERTEMPERATURE: OPTIONS_SENSOR_OVERTEMPERATURE, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYUNI_ID or dev_id_prefix == MODEL_SHELLYUNI_PREFIX: model = MODEL_SHELLYUNI inputs = 1 relays = 2 ext_humi_sensors = 1 ext_temp_sensors = 3 inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] relays_bin_sensors = [ SENSOR_INPUT, SENSOR_LONGPUSH, SENSOR_SHORTPUSH, SENSOR_OVERPOWER, ] relays_bin_sensors_entity_categories = [ None, None, None, ENTITY_CATEGORY_DIAGNOSTIC, ] relays_bin_sensors_pl = [PL_1_0, PL_1_0, PL_0_1, None] relays_bin_sensors_topics = [ None, TOPIC_INPUT_EVENT, TOPIC_INPUT_EVENT, TOPIC_RELAY, ] relays_bin_sensors_tpls = [None, TPL_LONGPUSH, TPL_SHORTPUSH, TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [None, None, None, DEVICE_CLASS_PROBLEM] sensors = { SENSOR_ADC: OPTIONS_SENSOR_ADC, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if ( model_id in (MODEL_SHELLYPLUG_ID, MODEL_SHELLYPLUG_E_ID) or dev_id_prefix == MODEL_SHELLYPLUG_PREFIX ): model = MODEL_SHELLYPLUG relays = 1 relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } relays_bin_sensors = [SENSOR_OVERPOWER] relays_bin_sensors_entity_categories = [ENTITY_CATEGORY_DIAGNOSTIC] relays_bin_sensors_pl = [None] relays_bin_sensors_topics = [TOPIC_RELAY] relays_bin_sensors_tpls = [TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [DEVICE_CLASS_PROBLEM] binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, } buttons = {BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE} if model_id == MODEL_SHELLYPLUG_US_ID or dev_id_prefix == MODEL_SHELLYPLUG_US_PREFIX: model = MODEL_SHELLYPLUG_US relays = 1 relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } relays_bin_sensors = [SENSOR_OVERPOWER] relays_bin_sensors_entity_categories = [ENTITY_CATEGORY_DIAGNOSTIC] relays_bin_sensors_pl = [None] relays_bin_sensors_topics = [TOPIC_RELAY] relays_bin_sensors_tpls = [TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [DEVICE_CLASS_PROBLEM] binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYPLUG_S_ID or dev_id_prefix == MODEL_SHELLYPLUG_S_PREFIX: model = MODEL_SHELLYPLUG_S relays = 1 relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } relays_bin_sensors = [SENSOR_OVERPOWER] relays_bin_sensors_entity_categories = [ENTITY_CATEGORY_DIAGNOSTIC] relays_bin_sensors_pl = [None] relays_bin_sensors_topics = [TOPIC_RELAY] relays_bin_sensors_tpls = [TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [DEVICE_CLASS_PROBLEM] sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_TEMPERATURE: OPTIONS_SENSOR_DEVICE_TEMPERATURE, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_OVERTEMPERATURE: OPTIONS_SENSOR_OVERTEMPERATURE, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLY4PRO_ID or dev_id_prefix == MODEL_SHELLY4PRO_PREFIX: model = MODEL_SHELLY4PRO relays = 4 relay_sensors = { SENSOR_POWER: OPTIONS_SENSOR_RELAY_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_RELAY_ENERGY, } relays_bin_sensors = [SENSOR_OVERPOWER, SENSOR_INPUT] relays_bin_sensors_entity_categories = [ENTITY_CATEGORY_DIAGNOSTIC, None] relays_bin_sensors_pl = [None, PL_1_0] relays_bin_sensors_topics = [TOPIC_RELAY, None] relays_bin_sensors_tpls = [TPL_OVERPOWER_RELAY, None] relays_bin_sensors_device_classes = [DEVICE_CLASS_PROBLEM, None] binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} bin_sensors_entity_categories = [ENTITY_CATEGORY_DIAGNOSTIC] bin_sensors_enabled = [True] bin_sensors_device_classes = [DEVICE_CLASS_UPDATE] bin_sensors_tpls = [TPL_NEW_FIRMWARE_FROM_ANNOUNCE] bin_sensors_topics = [TOPIC_ANNOUNCE] sensors = {SENSOR_IP: OPTIONS_SENSOR_IP} buttons = {BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE} if model_id == MODEL_SHELLYHT_ID or dev_id_prefix == MODEL_SHELLYHT_PREFIX: model = MODEL_SHELLYHT sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY, SENSOR_HUMIDITY: OPTIONS_SENSOR_HUMIDITY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE_F: OPTIONS_SENSOR_TEMPERATURE_F, SENSOR_TEMPERATURE: OPTIONS_SENSOR_TEMPERATURE, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_CLOUD: OPTIONS_SENSOR_CLOUD, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } battery_powered = True if model_id == MODEL_SHELLYMOTION_ID or dev_id_prefix == MODEL_SHELLYMOTION_PREFIX: model = MODEL_SHELLYMOTION buttons = { BUTTON_RESTART: OPTIONS_BUTTON_RESTART, BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, } sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY_MOTION, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_LUX: OPTIONS_SENSOR_LUX_MOTION, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_MOTION: OPTIONS_SENSOR_MOTION_MOTION, SENSOR_VIBRATION: OPTIONS_SENSOR_VIBRATION_MOTION, SENSOR_CHARGER: OPTIONS_SENSOR_CHARGER, SENSOR_CLOUD: OPTIONS_SENSOR_CLOUD, } battery_powered = True if model_id == MODEL_SHELLYMOTION2_ID or dev_id_prefix == MODEL_SHELLYMOTION2_PREFIX: model = MODEL_SHELLYMOTION2 buttons = { BUTTON_RESTART: OPTIONS_BUTTON_RESTART, BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, } sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY_MOTION, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_LUX: OPTIONS_SENSOR_LUX_MOTION, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE: OPTIONS_SENSOR_TEMPERATURE_MOTION, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_MOTION: OPTIONS_SENSOR_MOTION_MOTION, SENSOR_VIBRATION: OPTIONS_SENSOR_VIBRATION_MOTION, SENSOR_CHARGER: OPTIONS_SENSOR_CHARGER, SENSOR_CLOUD: OPTIONS_SENSOR_CLOUD, } battery_powered = True if model_id == MODEL_SHELLYGAS_ID or dev_id_prefix == MODEL_SHELLYGAS_PREFIX: model = MODEL_SHELLYGAS sensors = { SENSOR_CONCENTRATION: OPTIONS_SENSOR_CONCENTRATION, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_OPERATION: OPTIONS_SENSOR_OPERATION, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SELF_TEST: OPTIONS_SENSOR_SELF_TEST, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_VALVE: OPTIONS_SENSOR_VALVE, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_GAS: OPTIONS_SENSOR_GAS, } buttons = { BUTTON_MUTE: OPTIONS_BUTTON_MUTE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, BUTTON_SELF_TEST: OPTIONS_BUTTON_SELF_TEST, BUTTON_UNMUTE: OPTIONS_BUTTON_UNMUTE, BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_VALVE_CLOSE: OPTIONS_BUTTON_VALVE_CLOSE, BUTTON_VALVE_OPEN: OPTIONS_BUTTON_VALVE_OPEN, } if ( model_id in (MODEL_SHELLYBUTTON1_ID, MODEL_SHELLYBUTTON1V2_ID) or dev_id_prefix == MODEL_SHELLYBUTTON1_PREFIX ): model = MODEL_SHELLYBUTTON1 inputs = 1 inputs_types = [ VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS, VALUE_BUTTON_DOUBLE_PRESS, VALUE_BUTTON_TRIPLE_PRESS, ] sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_SHORTPUSH: OPTIONS_SENSOR_SHORTPUSH, SENSOR_DOUBLE_SHORTPUSH: OPTIONS_SENSOR_DOUBLE_SHORTPUSH, SENSOR_TRIPLE_SHORTPUSH: OPTIONS_SENSOR_TRIPLE_SHORTPUSH, SENSOR_LONGPUSH: OPTIONS_SENSOR_LONGPUSH, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_CHARGER: OPTIONS_SENSOR_CHARGER_BUTTON, } battery_powered = True if model_id == MODEL_SHELLYDW_ID or dev_id_prefix == MODEL_SHELLYDW_PREFIX: model = MODEL_SHELLYDW sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_LUX: OPTIONS_SENSOR_LUX, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TILT: OPTIONS_SENSOR_TILT, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_OPENING: OPTIONS_SENSOR_OPENING, SENSOR_VIBRATION: OPTIONS_SENSOR_VIBRATION_DW, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } battery_powered = True if model_id == MODEL_SHELLYDW2_ID or dev_id_prefix == MODEL_SHELLYDW2_PREFIX: model = MODEL_SHELLYDW2 sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_LUX: OPTIONS_SENSOR_LUX, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE_F: OPTIONS_SENSOR_TEMPERATURE_F, SENSOR_TEMPERATURE: OPTIONS_SENSOR_TEMPERATURE, SENSOR_TILT: OPTIONS_SENSOR_TILT, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_OPENING: OPTIONS_SENSOR_OPENING, SENSOR_VIBRATION: OPTIONS_SENSOR_VIBRATION_DW, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } battery_powered = True if model_id == MODEL_SHELLYSMOKE_ID or dev_id_prefix == MODEL_SHELLYSMOKE_PREFIX: model = MODEL_SHELLYSMOKE sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE: OPTIONS_SENSOR_TEMPERATURE, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_SMOKE: OPTIONS_SENSOR_SMOKE, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } battery_powered = True if model_id == MODEL_SHELLYSENSE_ID or dev_id_prefix == MODEL_SHELLYSENSE_PREFIX: model = MODEL_SHELLYSENSE sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_LUX: OPTIONS_SENSOR_LUX, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE: OPTIONS_SENSOR_TEMPERATURE, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_MOTION: OPTIONS_SENSOR_MOTION, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE_FROM_ANNOUNCE, SENSOR_CHARGER: OPTIONS_SENSOR_CHARGER_SENSE, } battery_powered = True if model_id == MODEL_SHELLYRGBW2_ID or dev_id_prefix == MODEL_SHELLYRGBW2_PREFIX: if mode not in (LIGHT_COLOR, LIGHT_WHITE): raise ValueError(f"mode value {mode} is not valid, check script configuration") model = MODEL_SHELLYRGBW2 inputs = 1 rgbw_lights = 1 white_lights = 4 white_lights = { 0: { KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT, KEY_COMMAND_TOPIC: TOPIC_WHITE_SET, KEY_STATE_TOPIC: TOPIC_WHITE_STATUS, }, 1: { KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT, KEY_COMMAND_TOPIC: TOPIC_WHITE_SET, KEY_STATE_TOPIC: TOPIC_WHITE_STATUS, }, 2: { KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT, KEY_COMMAND_TOPIC: TOPIC_WHITE_SET, KEY_STATE_TOPIC: TOPIC_WHITE_STATUS, }, 3: { KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT, KEY_COMMAND_TOPIC: TOPIC_WHITE_SET, KEY_STATE_TOPIC: TOPIC_WHITE_STATUS, }, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_LONGPUSH_0: OPTIONS_SENSOR_LONGPUSH_0, SENSOR_SHORTPUSH_0: OPTIONS_SENSOR_SHORTPUSH_0, } inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] lights_bin_sensors = [SENSOR_OVERPOWER] lights_bin_sensors_device_classes = [DEVICE_CLASS_PROBLEM] lights_bin_sensors_pl = [None] lights_bin_sensors_topics = [None] lights_bin_sensors_tpls = [TPL_OVERPOWER] if mode == LIGHT_COLOR: light_sensors = { SENSOR_POWER: OPTIONS_SENSOR_LIGHT_POWER_RGBW2_COLOR, SENSOR_ENERGY: OPTIONS_SENSOR_LIGHT_ENERGY_RGBW2_COLOR, } else: light_sensors = { SENSOR_POWER: OPTIONS_SENSOR_LIGHT_POWER_RGBW2_WHITE, SENSOR_ENERGY: OPTIONS_SENSOR_LIGHT_ENERGY_RGBW2_WHITE, } sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYDIMMER_ID or dev_id_prefix == MODEL_SHELLYDIMMER_PREFIX: model = MODEL_SHELLYDIMMER inputs = 2 white_lights = { 0: { KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT, KEY_COMMAND_TOPIC: TOPIC_LIGHT_SET, KEY_STATE_TOPIC: TOPIC_LIGHT_STATUS, } } inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE: OPTIONS_SENSOR_DEVICE_TEMPERATURE, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_OVERTEMPERATURE: OPTIONS_SENSOR_OVERTEMPERATURE, SENSOR_OVERLOAD: OPTIONS_SENSOR_OVERLOAD, SENSOR_LOADERROR: OPTIONS_SENSOR_LOADERROR, SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_INPUT_1: OPTIONS_SENSOR_INPUT_1, SENSOR_LONGPUSH_0: OPTIONS_SENSOR_LONGPUSH_0, SENSOR_LONGPUSH_1: OPTIONS_SENSOR_LONGPUSH_1, SENSOR_SHORTPUSH_0: OPTIONS_SENSOR_SHORTPUSH_0, SENSOR_SHORTPUSH_1: OPTIONS_SENSOR_SHORTPUSH_1, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } light_sensors = { SENSOR_POWER: OPTIONS_SENSOR_LIGHT_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_LIGHT_ENERGY, SENSOR_OVERPOWER_VALUE: OPTIONS_SENSOR_LIGHT_OVERPOWER_VALUE, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYDIMMER2_ID or dev_id_prefix == MODEL_SHELLYDIMMER2_PREFIX: model = MODEL_SHELLYDIMMER2 inputs = 2 inputs_types = [VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS] white_lights = { 0: { KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT, KEY_COMMAND_TOPIC: TOPIC_LIGHT_SET, KEY_STATE_TOPIC: TOPIC_LIGHT_STATUS, } } sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE: OPTIONS_SENSOR_DEVICE_TEMPERATURE, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_OVERTEMPERATURE: OPTIONS_SENSOR_OVERTEMPERATURE, SENSOR_OVERLOAD: OPTIONS_SENSOR_OVERLOAD, SENSOR_LOADERROR: OPTIONS_SENSOR_LOADERROR, SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_INPUT_1: OPTIONS_SENSOR_INPUT_1, SENSOR_LONGPUSH_0: OPTIONS_SENSOR_LONGPUSH_0, SENSOR_LONGPUSH_1: OPTIONS_SENSOR_LONGPUSH_1, SENSOR_SHORTPUSH_0: OPTIONS_SENSOR_SHORTPUSH_0, SENSOR_SHORTPUSH_1: OPTIONS_SENSOR_SHORTPUSH_1, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } light_sensors = { SENSOR_POWER: OPTIONS_SENSOR_LIGHT_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_LIGHT_ENERGY, SENSOR_OVERPOWER_VALUE: OPTIONS_SENSOR_LIGHT_OVERPOWER_VALUE, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYBULB_ID or dev_id_prefix == MODEL_SHELLYBULB_PREFIX: model = MODEL_SHELLYBULB rgbw_lights = 1 binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYBULBRGBW_ID or dev_id_prefix == MODEL_SHELLYBULBRGBW_PREFIX: model = MODEL_SHELLYBULBRGBW rgbw_lights = 1 light_sensors = { SENSOR_POWER: OPTIONS_SENSOR_LIGHT_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_LIGHT_ENERGY, } binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYDUO_ID or dev_id_prefix == MODEL_SHELLYDUO_PREFIX: model = MODEL_SHELLYDUO white_lights = { 0: { KEY_COLOR_TEMP_TEMPLATE: TPL_COLOR_TEMP_WHITE_LIGHT, KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT_DUO, KEY_COMMAND_TOPIC: TOPIC_LIGHT_SET, KEY_MAX_MIREDS: 370, KEY_MIN_MIREDS: 153, KEY_STATE_TOPIC: TOPIC_LIGHT_STATUS, } } light_sensors = { SENSOR_POWER: OPTIONS_SENSOR_LIGHT_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_LIGHT_ENERGY, } binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYVINTAGE_ID or dev_id_prefix == MODEL_SHELLYVINTAGE_PREFIX: model = MODEL_SHELLYVINTAGE white_lights = { 0: { KEY_COMMAND_ON_TEMPLATE: TPL_COMMAND_ON_WHITE_LIGHT, KEY_COMMAND_TOPIC: TOPIC_LIGHT_SET, KEY_STATE_TOPIC: TOPIC_LIGHT_STATUS, } } light_sensors = { SENSOR_POWER: OPTIONS_SENSOR_LIGHT_POWER, SENSOR_ENERGY: OPTIONS_SENSOR_LIGHT_ENERGY, } binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYEM_ID or dev_id_prefix == MODEL_SHELLYEM_PREFIX: model = MODEL_SHELLYEM relays = 1 meters = 2 relays_bin_sensors = [SENSOR_OVERPOWER] relays_bin_sensors_entity_categories = [ENTITY_CATEGORY_DIAGNOSTIC] relays_bin_sensors_pl = [None] relays_bin_sensors_topics = [TOPIC_RELAY] relays_bin_sensors_tpls = [TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [DEVICE_CLASS_PROBLEM] meter_sensors = { SENSOR_ENERGY: OPTIONS_SENSOR_ENERGY_METER, SENSOR_POWER: OPTIONS_SENSOR_POWER_METER, SENSOR_REACTIVE_POWER: OPTIONS_SENSOR_REACTIVE_POWER_METER, SENSOR_RETURNED_ENERGY: OPTIONS_SENSOR_RETURNED_ENERGY_METER, SENSOR_TOTAL_RETURNED: OPTIONS_SENSOR_TOTAL_RETURNED_METER, SENSOR_TOTAL: OPTIONS_SENSOR_TOTAL_METER, SENSOR_VOLTAGE: OPTIONS_SENSOR_VOLTAGE_METER, } binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLY3EM_ID or dev_id_prefix == MODEL_SHELLY3EM_PREFIX: model = MODEL_SHELLY3EM relays = 1 meters = 3 relays_bin_sensors = [SENSOR_OVERPOWER] relays_bin_sensors_entity_categories = [ENTITY_CATEGORY_DIAGNOSTIC] relays_bin_sensors_pl = [None] relays_bin_sensors_topics = [TOPIC_RELAY] relays_bin_sensors_tpls = [TPL_OVERPOWER_RELAY] relays_bin_sensors_device_classes = [DEVICE_CLASS_PROBLEM] meter_sensors = { SENSOR_CURRENT: OPTIONS_SENSOR_CURRENT_METER, SENSOR_ENERGY: OPTIONS_SENSOR_ENERGY_METER, SENSOR_POWER_FACTOR: OPTIONS_SENSOR_POWER_FACTOR_METER, SENSOR_POWER: OPTIONS_SENSOR_POWER_METER, SENSOR_RETURNED_ENERGY: OPTIONS_SENSOR_RETURNED_ENERGY_METER, SENSOR_TOTAL_RETURNED: OPTIONS_SENSOR_TOTAL_RETURNED_METER, SENSOR_TOTAL: OPTIONS_SENSOR_TOTAL_METER, SENSOR_VOLTAGE: OPTIONS_SENSOR_VOLTAGE_METER, } binary_sensors = {SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE} sensors = { SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYFLOOD_ID or dev_id_prefix == MODEL_SHELLYFLOOD_PREFIX: model = MODEL_SHELLYFLOOD sensors = { SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_TEMPERATURE_F: OPTIONS_SENSOR_TEMPERATURE_F, SENSOR_TEMPERATURE: OPTIONS_SENSOR_TEMPERATURE, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, } binary_sensors = { SENSOR_FLOOD: OPTIONS_SENSOR_FLOOD, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } battery_powered = True if model_id == MODEL_SHELLYI3_ID or dev_id_prefix == MODEL_SHELLYI3_PREFIX: model = MODEL_SHELLYI3 inputs = 3 inputs_types = [ VALUE_BUTTON_LONG_PRESS, VALUE_BUTTON_SHORT_PRESS, VALUE_BUTTON_DOUBLE_PRESS, VALUE_BUTTON_TRIPLE_PRESS, VALUE_BUTTON_SHORT_LONG_PRESS, VALUE_BUTTON_LONG_SHORT_PRESS, ] binary_sensors = { SENSOR_INPUT_0: OPTIONS_SENSOR_INPUT_0, SENSOR_INPUT_1: OPTIONS_SENSOR_INPUT_1, SENSOR_INPUT_2: OPTIONS_SENSOR_INPUT_2, SENSOR_SHORTPUSH_0: OPTIONS_SENSOR_SHORTPUSH_0, SENSOR_SHORTPUSH_1: OPTIONS_SENSOR_SHORTPUSH_1, SENSOR_SHORTPUSH_2: OPTIONS_SENSOR_SHORTPUSH_2, SENSOR_DOUBLE_SHORTPUSH_0: OPTIONS_SENSOR_DOUBLE_SHORTPUSH_0, SENSOR_DOUBLE_SHORTPUSH_1: OPTIONS_SENSOR_DOUBLE_SHORTPUSH_1, SENSOR_DOUBLE_SHORTPUSH_2: OPTIONS_SENSOR_DOUBLE_SHORTPUSH_2, SENSOR_TRIPLE_SHORTPUSH_0: OPTIONS_SENSOR_TRIPLE_SHORTPUSH_0, SENSOR_TRIPLE_SHORTPUSH_1: OPTIONS_SENSOR_TRIPLE_SHORTPUSH_1, SENSOR_TRIPLE_SHORTPUSH_2: OPTIONS_SENSOR_TRIPLE_SHORTPUSH_2, SENSOR_LONGPUSH_0: OPTIONS_SENSOR_LONGPUSH_0, SENSOR_LONGPUSH_1: OPTIONS_SENSOR_LONGPUSH_1, SENSOR_LONGPUSH_2: OPTIONS_SENSOR_LONGPUSH_2, SENSOR_LONGPUSH_SHORTPUSH_0: OPTIONS_SENSOR_LONGPUSH_SHORTPUSH_0, SENSOR_LONGPUSH_SHORTPUSH_1: OPTIONS_SENSOR_LONGPUSH_SHORTPUSH_1, SENSOR_LONGPUSH_SHORTPUSH_2: OPTIONS_SENSOR_LONGPUSH_SHORTPUSH_2, SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, } sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_UPTIME: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP_VALVE, SENSOR_TEMPERATURE_STATUS: OPTIONS_SENSOR_TEMPERATURE_STATUS, } buttons = { BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, BUTTON_RESTART: OPTIONS_BUTTON_RESTART, } if model_id == MODEL_SHELLYVALVE_ID: model = MODEL_SHELLYVALVE battery_powered = True climate_entity_option = { KEY_MAX_TEMP: 31, KEY_MIN_TEMP: 4, KEY_MODES: ["heat"], KEY_PRECISION: 0.1, KEY_TEMP_STEP: 0.5, } sensors = { SENSOR_RSSI: OPTIONS_SENSOR_RSSI, SENSOR_SSID: OPTIONS_SENSOR_SSID, SENSOR_LAST_RESTART: OPTIONS_SENSOR_UPTIME, SENSOR_IP: OPTIONS_SENSOR_IP, SENSOR_BATTERY: OPTIONS_SENSOR_BATTERY_VALVE, } binary_sensors = { SENSOR_FIRMWARE_UPDATE: OPTIONS_SENSOR_FIRMWARE_UPDATE, SENSOR_CHARGER: OPTIONS_SENSOR_CHARGER, SENSOR_CLOUD: OPTIONS_SENSOR_CLOUD, SENSOR_CALIBRATED: OPTIONS_SENSOR_CALIBRATED, } buttons = { BUTTON_RESTART: OPTIONS_BUTTON_RESTART, BUTTON_UPDATE_FIRMWARE: OPTIONS_BUTTON_UPDATE_FIRMWARE, } selectors = {SELECT_PROFILES: OPTIONS_SELECT_PROFILES} switches = { SWITCH_SCHEDULE: OPTIONS_SWITCH_SCHEDULE, SWITCH_ACCELERATED_HEATING: OPTIONS_SWITCH_ACCELERATED_HEATING, } numbers = { NUMBER_VALVE_POSITION: OPTIONS_NUMBER_VALVE_POSITION, NUMBER_MINIMAL_VALVE_POSITION: OPTIONS_NUMBER_MINIMAL_VALVE_POSITION, NUMBER_BOOST_TIME: OPTIONS_BOOST_TIME, } device_config = get_device_config(dev_id) if device_config.get(CONF_DEVICE_NAME): device_name = device_config[CONF_DEVICE_NAME] elif ignore_device_model: device_name = clean_name(dev_id) else: device_name = f"{model} {dev_id.split('-')[-1]}" device_info = { KEY_CONNECTIONS: [[KEY_MAC, format_mac(mac)]], KEY_NAME: device_name, KEY_MODEL: model, KEY_SW_VERSION: fw_ver, KEY_HW_VERSION: f"gen1 ({model_id})", KEY_MANUFACTURER: ATTR_MANUFACTURER, KEY_CONFIGURATION_URL: f"http://{host}/", } default_topic = f"shellies/{dev_id}/" if battery_powered: if model == MODEL_SHELLYMOTION: expire_after = device_config.get( CONF_EXPIRE_AFTER, EXPIRE_AFTER_FOR_SHELLY_MOTION ) elif model == MODEL_SHELLYVALVE: expire_after = device_config.get( CONF_EXPIRE_AFTER, EXPIRE_AFTER_FOR_SHELLY_VALVE ) elif device_config.get(CONF_POWERED) == ATTR_POWER_AC and model in ( MODEL_SHELLYBUTTON1, MODEL_SHELLYSENSE, ): no_battery_sensor = True battery_powered = False elif device_config.get(CONF_POWERED): no_battery_sensor = True expire_after = device_config.get(CONF_EXPIRE_AFTER, EXPIRE_AFTER_FOR_AC_POWERED) else: expire_after = device_config.get( CONF_EXPIRE_AFTER, EXPIRE_AFTER_FOR_BATTERY_POWERED ) if expire_after and not isinstance(expire_after, int): raise TypeError( f"expire_after value {expire_after} is not an integer, check script configuration" ) # numbers for number, number_options in numbers.items(): config_topic = f"{disc_prefix}/number/{dev_id}-{number}/config".encode( "ascii", "ignore" ).decode("utf-8") payload = { KEY_NAME: f"{device_name} {clean_name(number)}", KEY_COMMAND_TOPIC: number_options[KEY_COMMAND_TOPIC], KEY_MAX: number_options[KEY_MAX], KEY_MIN: number_options[KEY_MIN], KEY_STEP: number_options[KEY_STEP], KEY_STATE_TOPIC: number_options[KEY_STATE_TOPIC], KEY_VALUE_TEMPLATE: number_options[KEY_VALUE_TEMPLATE], KEY_UNIT: number_options[KEY_UNIT], KEY_ENABLED_BY_DEFAULT: str(number_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-{number}".lower(), KEY_QOS: qos, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_DEVICE: device_info, "~": default_topic, } if number_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = number_options[KEY_ENTITY_CATEGORY] if number_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = number_options[KEY_DEVICE_CLASS] if number_options.get(ATTR_ICON): payload[KEY_ICON] = number_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # switches (not relays) for switch, switch_options in switches.items(): config_topic = f"{disc_prefix}/switch/{dev_id}-{switch}/config".encode( "ascii", "ignore" ).decode("utf-8") payload = { KEY_NAME: f"{device_name} {clean_name(switch)}", KEY_COMMAND_TOPIC: switch_options[KEY_COMMAND_TOPIC], KEY_PAYLOAD_OFF: switch_options[KEY_PAYLOAD_OFF], KEY_PAYLOAD_ON: switch_options[KEY_PAYLOAD_ON], KEY_STATE_TOPIC: switch_options[KEY_STATE_TOPIC], KEY_STATE_OFF: switch_options[KEY_STATE_OFF], KEY_STATE_ON: switch_options[KEY_STATE_ON], KEY_VALUE_TEMPLATE: switch_options[KEY_VALUE_TEMPLATE], KEY_ENABLED_BY_DEFAULT: str(switch_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-{switch}".lower(), KEY_QOS: qos, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_DEVICE: device_info, "~": default_topic, } if switch_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = switch_options[KEY_ENTITY_CATEGORY] if switch_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = switch_options[KEY_DEVICE_CLASS] if switch_options.get(ATTR_ICON): payload[KEY_ICON] = switch_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # selectors for select, select_options in selectors.items(): config_topic = f"{disc_prefix}/select/{dev_id}-{select}/config".encode( "ascii", "ignore" ).decode("utf-8") payload = { KEY_NAME: f"{device_name} {clean_name(select)}", KEY_COMMAND_TOPIC: select_options[KEY_COMMAND_TOPIC], KEY_COMMAND_TEMPLATE: TPL_COMMAND_PROFILES, KEY_OPTIONS: select_options[KEY_OPTIONS], KEY_STATE_TOPIC: select_options[KEY_STATE_TOPIC], KEY_VALUE_TEMPLATE: select_options[KEY_VALUE_TEMPLATE], KEY_ENABLED_BY_DEFAULT: str(select_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-{select}".lower(), KEY_QOS: qos, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_DEVICE: device_info, "~": default_topic, } if select_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = select_options[KEY_ENTITY_CATEGORY] if select_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = select_options[KEY_DEVICE_CLASS] if select_options.get(ATTR_ICON): payload[KEY_ICON] = select_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # buttons for button, button_options in buttons.items(): config_topic = f"{disc_prefix}/button/{dev_id}-{button}/config".encode( "ascii", "ignore" ).decode("utf-8") payload = { KEY_NAME: f"{device_name} {clean_name(button)}", KEY_COMMAND_TOPIC: button_options[KEY_COMMAND_TOPIC], KEY_PAYLOAD_PRESS: button_options[KEY_PAYLOAD_PRESS], KEY_ENABLED_BY_DEFAULT: str(button_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-{button}".lower(), KEY_QOS: qos, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_DEVICE: device_info, "~": default_topic, } if button_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = button_options[KEY_ENTITY_CATEGORY] if button_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = button_options[KEY_DEVICE_CLASS] if button_options.get(ATTR_ICON): payload[KEY_ICON] = button_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # climate entities if climate_entity_option: temperature_command_topic = "~thermostat/0/command/target_t" config_topic = f"{disc_prefix}/climate/{dev_id}/config".encode( "ascii", "ignore" ).decode("utf-8") payload = { KEY_NAME: device_name, KEY_ACTION_TOPIC: TOPIC_INFO, KEY_ACTION_TEMPLATE: TPL_ACTION_TEMPLATE.format( min_temp=climate_entity_option[KEY_MIN_TEMP] ), KEY_CURRENT_TEMPERATURE_TOPIC: TOPIC_INFO, KEY_CURRENT_TEMPERATURE_TEMPLATE: TPL_CURRENT_TEMPERATURE, KEY_TEMPERATURE_STATE_TOPIC: TOPIC_INFO, KEY_TEMPERATURE_STATE_TEMPLATE: TPL_TARGET_TEMPERATURE, KEY_TEMPERATURE_COMMAND_TOPIC: temperature_command_topic, KEY_TEMPERATURE_COMMAND_TEMPLATE: TPL_SET_TARGET_TEMPERATURE, KEY_TEMP_STEP: climate_entity_option[KEY_TEMP_STEP], KEY_MODE_STATE_TOPIC: TOPIC_INFO, KEY_MODE_STATE_TEMPLATE: "heat", KEY_UNIQUE_ID: f"{dev_id}".lower(), KEY_OPTIMISTIC: VALUE_FALSE, KEY_QOS: qos, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_DEVICE: device_info, "~": default_topic, } payload.update(climate_entity_option) if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # rollers for roller_id in range(rollers): if device_config.get(CONF_POSITION_TEMPLATE): position_template = device_config[CONF_POSITION_TEMPLATE] else: position_template = TPL_POSITION set_position_template = device_config.get(CONF_SET_POSITION_TEMPLATE, None) if device_config.get(f"roller-{roller_id}-name"): roller_name = device_config[f"roller-{roller_id}-name"] else: roller_name = f"{device_name} Roller {roller_id}" device_class = None if device_config.get(f"roller-{roller_id}-class"): if device_config[f"roller-{roller_id}-class"] in ROLLER_DEVICE_CLASSES: device_class = device_config[f"roller-{roller_id}-class"] else: wrong_class = device_config[f"roller-{roller_id}-class"] logger.error( # noqa: F821 f"{wrong_class} is the wrong roller class, the default value None was used" ) state_topic = f"~roller/{roller_id}" config_topic = f"{disc_prefix}/cover/{dev_id}-roller-{roller_id}/config".encode( "ascii", "ignore" ).decode("utf-8") if roller_mode: payload = { KEY_NAME: roller_name, KEY_COMMAND_TOPIC: f"{state_topic}/command", KEY_POSITION_TOPIC: f"{state_topic}/pos", KEY_STATE_TOPIC: state_topic, KEY_STATE_CLOSING: VALUE_CLOSE, KEY_STATE_OPENING: VALUE_OPEN, KEY_STATE_STOPPED: VALUE_STOP, KEY_POSITION_TEMPLATE: position_template, KEY_SET_POSITION_TOPIC: f"{state_topic}/command/pos", KEY_PAYLOAD_OPEN: VALUE_OPEN, KEY_PAYLOAD_CLOSE: VALUE_CLOSE, KEY_PAYLOAD_STOP: VALUE_STOP, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_UNIQUE_ID: f"{dev_id}-roller-{roller_id}".lower(), KEY_OPTIMISTIC: str(optimistic).lower(), KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if set_position_template: payload[KEY_SET_POSITION_TEMPLATE] = set_position_template if device_class: payload[KEY_DEVICE_CLASS] = device_class else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # relays for relay_id in range(relays): if device_config.get(f"relay-{relay_id}-name"): relay_name = device_config[f"relay-{relay_id}-name"] else: relay_name = f"{device_name} Relay {relay_id}" state_topic = f"~relay/{relay_id}" config_component = COMP_SWITCH if device_config.get(f"relay-{relay_id}"): config_component = device_config[f"relay-{relay_id}"] for component in relay_components: config_topic = ( f"{disc_prefix}/{component}/{dev_id}-relay-{relay_id}/config".encode( "ascii", "ignore" ).decode("utf-8") ) if component == config_component and not roller_mode: payload = { KEY_NAME: relay_name, KEY_COMMAND_TOPIC: f"{state_topic}/command", KEY_STATE_TOPIC: state_topic, KEY_PAYLOAD_OFF: VALUE_OFF, KEY_PAYLOAD_ON: VALUE_ON, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_UNIQUE_ID: f"{dev_id}-relay-{relay_id}".lower(), KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # relay sensors for sensor, sensor_options in relay_sensors.items(): force_update = False if isinstance(device_config.get(CONF_FORCE_UPDATE_SENSORS), bool): force_update = device_config.get(CONF_FORCE_UPDATE_SENSORS) config_topic = ( f"{disc_prefix}/sensor/{dev_id}-{sensor}-{relay_id}/config".encode( "ascii", "ignore" ).decode("utf-8") ) payload = { KEY_NAME: f"{device_name} {clean_name(sensor)} {relay_id}", KEY_STATE_TOPIC: sensor_options[KEY_STATE_TOPIC].format(relay_id=relay_id), KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_FORCE_UPDATE: str(force_update).lower(), KEY_ENABLED_BY_DEFAULT: str(sensor_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-relay-{sensor}-{relay_id}".lower(), KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if sensor_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = sensor_options[KEY_ENTITY_CATEGORY] if sensor_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = sensor_options[KEY_DEVICE_CLASS] if sensor_options.get(KEY_STATE_CLASS): payload[KEY_STATE_CLASS] = sensor_options[KEY_STATE_CLASS] if sensor_options.get(KEY_UNIT): payload[KEY_UNIT] = sensor_options[KEY_UNIT] if sensor_options.get(KEY_VALUE_TEMPLATE): payload[KEY_VALUE_TEMPLATE] = sensor_options[KEY_VALUE_TEMPLATE] if sensor_options.get(ATTR_ICON): payload[KEY_ICON] = sensor_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" if roller_mode: payload = "" mqtt_publish(config_topic, payload, retain) # relay's binary sensors for bin_sensor_id in range(len(relays_bin_sensors)): push_off_delay = True if isinstance(device_config.get(CONF_PUSH_OFF_DELAY), bool): push_off_delay = device_config.get(CONF_PUSH_OFF_DELAY) unique_id = f"{dev_id}-{relays_bin_sensors[bin_sensor_id]}-{relay_id}".lower() config_topic = f"{disc_prefix}/binary_sensor/{dev_id}-{relays_bin_sensors[bin_sensor_id]}-{relay_id}/config".encode( "ascii", "ignore" ).decode( "utf-8" ) if device_config.get(f"relay-{relay_id}-name"): sensor_name = f"{device_config[f'relay-{relay_id}-name']} {clean_name(relays_bin_sensors[bin_sensor_id])}" else: sensor_name = f"{device_name} {clean_name(relays_bin_sensors[bin_sensor_id])} {relay_id}" if relays_bin_sensors_topics and relays_bin_sensors_topics[bin_sensor_id]: state_topic = f"{relays_bin_sensors_topics[bin_sensor_id]}/{relay_id}" else: state_topic = f"~{relays_bin_sensors[bin_sensor_id]}/{relay_id}" if not roller_mode: payload = { KEY_NAME: sensor_name, KEY_STATE_TOPIC: state_topic, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_UNIQUE_ID: unique_id, KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if ( relays_bin_sensors[bin_sensor_id] in ( SENSOR_LONGPUSH, SENSOR_LONGPUSH_0, SENSOR_LONGPUSH_1, SENSOR_LONGPUSH_2, SENSOR_SHORTPUSH, SENSOR_SHORTPUSH_0, SENSOR_SHORTPUSH_1, SENSOR_SHORTPUSH_2, SENSOR_DOUBLE_SHORTPUSH, SENSOR_DOUBLE_SHORTPUSH_0, SENSOR_DOUBLE_SHORTPUSH_1, SENSOR_DOUBLE_SHORTPUSH_2, SENSOR_TRIPLE_SHORTPUSH, SENSOR_TRIPLE_SHORTPUSH_0, SENSOR_TRIPLE_SHORTPUSH_1, SENSOR_TRIPLE_SHORTPUSH_2, ) and push_off_delay ): payload[KEY_OFF_DELAY] = OFF_DELAY if relays_bin_sensors_entity_categories[bin_sensor_id]: payload[KEY_ENTITY_CATEGORY] = relays_bin_sensors_entity_categories[ bin_sensor_id ] if relays_bin_sensors_tpls[bin_sensor_id]: payload[KEY_VALUE_TEMPLATE] = relays_bin_sensors_tpls[bin_sensor_id] else: payload[KEY_PAYLOAD_ON] = relays_bin_sensors_pl[bin_sensor_id][VALUE_ON] payload[KEY_PAYLOAD_OFF] = relays_bin_sensors_pl[bin_sensor_id][ VALUE_OFF ] if relays_bin_sensors_device_classes[bin_sensor_id]: payload[KEY_DEVICE_CLASS] = relays_bin_sensors_device_classes[ bin_sensor_id ] if ( model in ( MODEL_SHELLY1PM, MODEL_SHELLY2, MODEL_SHELLY25, MODEL_SHELLY4PRO, MODEL_SHELLYPLUG, MODEL_SHELLYPLUG_S, MODEL_SHELLYPLUG_US, ) and relays_bin_sensors[bin_sensor_id] == SENSOR_OVERPOWER ): payload[ KEY_JSON_ATTRIBUTES_TOPIC ] = f"{relays_bin_sensors_topics[bin_sensor_id]}/{relay_id}/{TOPIC_OVERPOWER_VALUE}" payload[KEY_JSON_ATTRIBUTES_TEMPLATE] = TPL_OVERPOWER_VALUE_TO_JSON else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # sensors for sensor, sensor_options in sensors.items(): use_fahrenheit = device_config.get(CONF_USE_FAHRENHEIT) force_update = False if isinstance(device_config.get(CONF_FORCE_UPDATE_SENSORS), bool): force_update = device_config.get(CONF_FORCE_UPDATE_SENSORS) config_topic = f"{disc_prefix}/sensor/{dev_id}-{sensor}/config".encode( "ascii", "ignore" ).decode("utf-8") if model in (MODEL_SHELLY2, MODEL_SHELLY25) and sensor in ( SENSOR_ENERGY, SENSOR_POWER, ): unique_id = f"{dev_id}-relay-{sensor}".lower() else: unique_id = f"{dev_id}-{sensor}".lower() if sensor in (SENSOR_SSID, SENSOR_ADC, SENSOR_IP): sensor_name = f"{device_name} {sensor.upper()}" elif sensor == SENSOR_UPTIME: sensor_name = f"{device_name} Last Restart" elif sensor == SENSOR_RSSI: sensor_name = f"{device_name} WiFi Signal" elif sensor == SENSOR_TEMPERATURE_F: sensor_name = f"{device_name} Temperature" else: sensor_name = f"{device_name} {clean_name(sensor)}" payload = { KEY_NAME: sensor_name, KEY_STATE_TOPIC: sensor_options[KEY_STATE_TOPIC], KEY_FORCE_UPDATE: str(force_update).lower(), KEY_ENABLED_BY_DEFAULT: str(sensor_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: unique_id, KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if sensor_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = sensor_options[KEY_ENTITY_CATEGORY] if sensor_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = sensor_options[KEY_DEVICE_CLASS] if sensor_options.get(KEY_STATE_CLASS): payload[KEY_STATE_CLASS] = sensor_options[KEY_STATE_CLASS] if model == MODEL_SHELLYDW2 and sensor == SENSOR_LUX: payload[KEY_JSON_ATTRIBUTES_TOPIC] = f"~sensor/{SENSOR_ILLUMINATION}" payload[KEY_JSON_ATTRIBUTES_TEMPLATE] = TPL_ILLUMINATION_TO_JSON if sensor_options.get(KEY_UNIT): payload[KEY_UNIT] = sensor_options[KEY_UNIT] if sensor_options.get(KEY_VALUE_TEMPLATE): payload[KEY_VALUE_TEMPLATE] = sensor_options[KEY_VALUE_TEMPLATE] if sensor_options.get(ATTR_ICON): payload[KEY_ICON] = sensor_options[ATTR_ICON] if battery_powered and model not in (MODEL_SHELLYDW, MODEL_SHELLYDW2): payload[KEY_EXPIRE_AFTER] = expire_after elif not battery_powered: payload[KEY_AVAILABILITY_TOPIC] = TOPIC_ONLINE payload[KEY_PAYLOAD_AVAILABLE] = VALUE_TRUE payload[KEY_PAYLOAD_NOT_AVAILABLE] = VALUE_FALSE if no_battery_sensor and sensor == SENSOR_BATTERY: payload = "" if use_fahrenheit and sensor == SENSOR_TEMPERATURE: payload = "" if not use_fahrenheit and sensor == SENSOR_TEMPERATURE_F: payload = "" if ( model == MODEL_SHELLY25 and sensor in (SENSOR_ENERGY, SENSOR_POWER) and not roller_mode ): payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # inputs for input_id in range(inputs): config_topic = f"{disc_prefix}/device_automation/{dev_id}-input-{input_id}/button_release/config".encode( "ascii", "ignore" ).decode( "utf-8" ) topic = f"shellies/{dev_id}/input/{input_id}" payload = { KEY_AUTOMATION_TYPE: VALUE_TRIGGER, KEY_TOPIC: topic, KEY_PAYLOAD: "0", KEY_QOS: qos, KEY_DEVICE: device_info, KEY_TYPE: VALUE_BUTTON_SHORT_RELEASE, KEY_SUBTYPE: f"button_{input_id + 1}", } if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) topic = f"shellies/{dev_id}/input_event/{input_id}" for event in inputs_types: config_topic = f"{disc_prefix}/device_automation/{dev_id}-input-{input_id}/{event}/config".encode( "ascii", "ignore" ).decode( "utf-8" ) payload = { KEY_AUTOMATION_TYPE: VALUE_TRIGGER, KEY_TOPIC: topic, KEY_PAYLOAD: DEVICE_TRIGGERS_MAP[event], KEY_VALUE_TEMPLATE: "{{value_json.event}}", KEY_QOS: qos, KEY_DEVICE: device_info, KEY_TYPE: event, KEY_SUBTYPE: f"button_{input_id + 1}", } if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # external temperature sensors for sensor_id in range(ext_temp_sensors): force_update = False if isinstance(device_config.get(CONF_FORCE_UPDATE_SENSORS), bool): force_update = device_config.get(CONF_FORCE_UPDATE_SENSORS) unique_id = f"{dev_id}-ext-temperature-{sensor_id}".lower() config_topic = ( f"{disc_prefix}/sensor/{dev_id}-ext-temperature-{sensor_id}/config".encode( "ascii", "ignore" ).decode("utf-8") ) sensor_name = f"{device_name} External Temperature {sensor_id}" state_topic = f"~{SENSOR_EXT_TEMPERATURE}/{sensor_id}" if device_config.get(f"ext-temperature-{sensor_id}"): payload = { KEY_NAME: sensor_name, KEY_STATE_TOPIC: state_topic, KEY_VALUE_TEMPLATE: TPL_TEMPERATURE_EXT, KEY_STATE_CLASS: STATE_CLASS_MEASUREMENT, KEY_UNIT: UNIT_CELSIUS, KEY_DEVICE_CLASS: SENSOR_TEMPERATURE, KEY_FORCE_UPDATE: str(force_update).lower(), KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_UNIQUE_ID: unique_id, KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # external humidity sensors for sensor_id in range(ext_humi_sensors): force_update = False if isinstance(device_config.get(CONF_FORCE_UPDATE_SENSORS), bool): force_update = device_config.get(CONF_FORCE_UPDATE_SENSORS) unique_id = f"{dev_id}-ext-humidity-{sensor_id}".lower() config_topic = ( f"{disc_prefix}/sensor/{dev_id}-ext-humidity-{sensor_id}/config".encode( "ascii", "ignore" ).decode("utf-8") ) sensor_name = f"{device_name} External Humidity {sensor_id}" state_topic = f"~{SENSOR_EXT_HUMIDITY}/{sensor_id}" if device_config.get(f"ext-temperature-{sensor_id}"): payload = { KEY_NAME: sensor_name, KEY_STATE_TOPIC: state_topic, KEY_VALUE_TEMPLATE: TPL_HUMIDITY_EXT, KEY_STATE_CLASS: STATE_CLASS_MEASUREMENT, KEY_UNIT: UNIT_PERCENT, KEY_DEVICE_CLASS: SENSOR_HUMIDITY, KEY_FORCE_UPDATE: str(force_update).lower(), KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_UNIQUE_ID: unique_id, KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # binary sensors for sensor, sensor_options in binary_sensors.items(): push_off_delay = True if isinstance(device_config.get(CONF_PUSH_OFF_DELAY), bool): push_off_delay = device_config.get(CONF_PUSH_OFF_DELAY) config_topic = ( f"{disc_prefix}/binary_sensor/{dev_id}-{make_id(sensor)}/config".encode( "ascii", "ignore" ).decode("utf-8") ) if sensor == SENSOR_EXT_SWITCH: sensor_name = f"{device_name} External Switch" else: sensor_name = f"{device_name} {clean_name(sensor)}" state_topic = sensor_options[KEY_STATE_TOPIC] payload = { KEY_NAME: sensor_name, KEY_STATE_TOPIC: state_topic, KEY_ENABLED_BY_DEFAULT: str(sensor_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-{make_id(sensor)}".lower(), KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if sensor_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = sensor_options[KEY_ENTITY_CATEGORY] if sensor_options.get(KEY_VALUE_TEMPLATE): payload[KEY_VALUE_TEMPLATE] = sensor_options[KEY_VALUE_TEMPLATE] else: payload[KEY_PAYLOAD_ON] = sensor_options[KEY_PAYLOAD_ON] payload[KEY_PAYLOAD_OFF] = sensor_options[KEY_PAYLOAD_OFF] if battery_powered and model not in (MODEL_SHELLYDW, MODEL_SHELLYDW2): payload[KEY_EXPIRE_AFTER] = expire_after elif not battery_powered: payload[KEY_AVAILABILITY_TOPIC] = TOPIC_ONLINE payload[KEY_PAYLOAD_AVAILABLE] = VALUE_TRUE payload[KEY_PAYLOAD_NOT_AVAILABLE] = VALUE_FALSE if sensor_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = sensor_options[KEY_DEVICE_CLASS] if ( sensor in ( SENSOR_LONGPUSH, SENSOR_LONGPUSH_0, SENSOR_LONGPUSH_1, SENSOR_LONGPUSH_2, SENSOR_SHORTPUSH, SENSOR_SHORTPUSH_0, SENSOR_SHORTPUSH_1, SENSOR_SHORTPUSH_2, SENSOR_DOUBLE_SHORTPUSH, SENSOR_DOUBLE_SHORTPUSH_0, SENSOR_DOUBLE_SHORTPUSH_1, SENSOR_DOUBLE_SHORTPUSH_2, SENSOR_TRIPLE_SHORTPUSH, SENSOR_TRIPLE_SHORTPUSH_0, SENSOR_TRIPLE_SHORTPUSH_1, SENSOR_TRIPLE_SHORTPUSH_2, ) and push_off_delay ): payload[KEY_OFF_DELAY] = OFF_DELAY if ( model == MODEL_SHELLYRGBW2 and mode == LIGHT_WHITE and sensor == SENSOR_OVERPOWER ): payload = "" if model in (MODEL_SHELLYDW, MODEL_SHELLYDW2) and sensor == SENSOR_OPENING: payload[KEY_FORCE_UPDATE] = VALUE_TRUE if model == MODEL_SHELLYGAS and sensor == SENSOR_GAS: payload[KEY_JSON_ATTRIBUTES_TOPIC] = state_topic payload[KEY_JSON_ATTRIBUTES_TEMPLATE] = TPL_GAS_TO_JSON if ( sensor == SENSOR_FIRMWARE_UPDATE and sensor_options.get(KEY_VALUE_TEMPLATE) == TPL_NEW_FIRMWARE_FROM_INFO ): payload[KEY_JSON_ATTRIBUTES_TOPIC] = TOPIC_INFO payload[KEY_JSON_ATTRIBUTES_TEMPLATE] = TPL_UPDATE_TO_JSON if ( model == MODEL_SHELLY1 and sensor == SENSOR_EXT_SWITCH and not device_config.get(CONF_EXT_SWITCH) ): payload = "" if ( model == MODEL_SHELLYHT and sensor == SENSOR_CLOUD and device_config.get(CONF_POWERED) != ATTR_POWER_AC ): payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # color lights for light_id in range(rgbw_lights): if device_config.get(f"light-{light_id}-name"): light_name = device_config[f"light-{light_id}-name"] else: light_name = f"{device_name} Light {light_id}" state_topic = f"~color/{light_id}/status" command_topic = f"~color/{light_id}/set" availability_topic = TOPIC_ONLINE unique_id = f"{dev_id}-light-{light_id}".lower() config_topic = f"{disc_prefix}/light/{dev_id}-{light_id}/config".encode( "ascii", "ignore" ).decode("utf-8") if mode == LIGHT_COLOR and model == MODEL_SHELLYRGBW2: payload = ( '{"schema":"template",' '"name":"' + light_name + '",' '"cmd_t":"' + command_topic + '",' '"stat_t":"' + state_topic + '",' '"avty_t":"' + availability_topic + '",' '"pl_avail":"true",' '"pl_not_avail":"false",' '"fx_list":["Off", "Meteor Shower", "Gradual Change", "Flash"],' '"cmd_on_tpl":"{\\"turn\\":\\"on\\"{%if brightness is defined%},\\"gain\\":{{brightness|float|multiply(0.3922)|round}}{%endif%}{%if red is defined and green is defined and blue is defined%},\\"red\\":{{red}},\\"green\\":{{green}},\\"blue\\":{{blue}}{%endif%}{%if effect is defined%}{%if effect==\\"Meteor Shower\\"%}\\"effect\\":1{%elif effect==\\"Gradual Change\\"%}\\"effect\\":2{%elif effect==\\"Flash\\"%}\\"effect\\":3{%else%}\\"effect\\":0{%endif%}{%else%}\\"effect\\":0{%endif%}{%if transition is defined%},\\"transition\\":{{min(transition|multiply(1000),' + str(MAX_TRANSITION) + ')}}{%endif%}}",' '"cmd_off_tpl":"{\\"turn\\":\\"off\\"{%if transition is defined%},\\"transition\\":{{min(transition|multiply(1000),' + str(MAX_TRANSITION) + ')}}{%endif%}}",' '"stat_tpl":"{%if value_json.ison%}on{%else%}off{%endif%}",' '"bri_tpl":"{{value_json.gain|float|multiply(2.55)|round}}",' '"r_tpl":"{{value_json.red}}",' '"g_tpl":"{{value_json.green}}",' '"b_tpl":"{{value_json.blue}}",' '"fx_tpl":"{%if value_json.effect==1%}Meteor Shower{%elif value_json.effect==2%}Gradual Change{%elif value_json.effect==3%}Flash{%else%}Off{%endif%}",' '"uniq_id":"' + unique_id + '",' '"qos":"' + str(qos) + '",' '"dev": {"cns":[["' + KEY_MAC + '","' + format_mac(mac) + '"]],' '"name":"' + device_name + '",' '"mdl":"' + model + '",' '"sw":"' + fw_ver + '",' '"mf":"' + ATTR_MANUFACTURER + '"},' '"~":"' + default_topic + '"}' ) elif model in (MODEL_SHELLYBULB, MODEL_SHELLYBULBRGBW): payload = ( '{"schema":"template",' '"name":"' + light_name + '",' '"cmd_t":"' + command_topic + '",' '"stat_t":"' + state_topic + '",' '"avty_t":"' + availability_topic + '",' '"pl_avail":"true",' '"pl_not_avail":"false",' '"fx_list":["Off", "Meteor Shower", "Gradual Change", "Breath", "Flash", "On/Off Gradual", "Red/Green Change"],' '"cmd_on_tpl":"{\\"turn\\":\\"on\\",\\"mode\\":\\"color\\",{%if red is defined and green is defined and blue is defined%}\\"red\\":{{red}},\\"green\\":{{green}},\\"blue\\":{{blue}},{%endif%}{%if brightness is defined%}\\"gain\\":{{brightness|float|multiply(0.3922)|round}},{%endif%}{%if effect is defined%}{%if effect == \\"Meteor Shower\\"%}\\"effect\\":1{%elif effect == \\"Gradual Change\\"%}\\"effect\\":2{%elif effect == \\"Breath\\"%}\\"effect\\":3{%elif effect == \\"Flash\\"%}\\"effect\\":4{%elif effect == \\"On/Off Gradual\\"%}\\"effect\\":5{%elif effect == \\"Red/Green Change\\"%}\\"effect\\":6{%else%}\\"effect\\":0{%endif%}{%else%}\\"effect\\":0{%endif%}{%if transition is defined%},\\"transition\\":{{min(transition|multiply(1000),' + str(MAX_TRANSITION) + ')}}{%endif%}}",' '"cmd_off_tpl":"{\\"turn\\":\\"off\\",\\"mode\\":\\"color\\",\\"effect\\": 0{%if transition is defined%},\\"transition\\":{{min(transition|multiply(1000),' + str(MAX_TRANSITION) + ')}}{%endif%}}",' '"stat_tpl":"{%if value_json.ison==true and value_json.mode==\\"color\\"%}on{%else%}off{%endif%}",' '"bri_tpl":"{{value_json.gain|float|multiply(2.55)|round}}",' '"r_tpl":"{{value_json.red}}",' '"g_tpl":"{{value_json.green}}",' '"b_tpl":"{{value_json.blue}}",' '"fx_tpl":"{%if value_json.effect==1%}Meteor Shower{%elif value_json.effect==2%}Gradual Change{%elif value_json.effect==3%}Breath{%elif value_json.effect==4%}Flash{%elif value_json.effect==5%}On/Off Gradual{%elif value_json.effect==6%}Red/Green Change{%else%}Off{%endif%}",' '"uniq_id":"' + unique_id + '",' '"qos":"' + str(qos) + '",' '"dev": {"cns":[["' + KEY_MAC + '","' + format_mac(mac) + '"]],' '"name":"' + device_name + '",' '"mdl":"' + model + '",' '"sw":"' + fw_ver + '",' '"mf":"' + ATTR_MANUFACTURER + '"},' '"~":"' + default_topic + '"}' ) else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # color light's binary sensors for bin_sensor_id in range(len(lights_bin_sensors)): sensor_name = ( f"{device_name} {clean_name(lights_bin_sensors[bin_sensor_id])} {light_id}" ) config_topic = f"{disc_prefix}/binary_sensor/{dev_id}-color-{lights_bin_sensors[bin_sensor_id]}-{light_id}/config".encode( "ascii", "ignore" ).decode( "utf-8" ) unique_id = ( f"{dev_id}-color-{lights_bin_sensors[bin_sensor_id]}-{light_id}".lower() ) if lights_bin_sensors[bin_sensor_id] == SENSOR_INPUT: state_topic = f"~{lights_bin_sensors[bin_sensor_id]}/{light_id}" else: state_topic = f"~color/{light_id}/status" if mode == LIGHT_COLOR: payload = { KEY_NAME: sensor_name, KEY_STATE_TOPIC: state_topic, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_UNIQUE_ID: unique_id, KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if ( lights_bin_sensors_device_classes and lights_bin_sensors_device_classes[bin_sensor_id] ): payload[KEY_DEVICE_CLASS] = lights_bin_sensors_device_classes[ bin_sensor_id ] if lights_bin_sensors_tpls and lights_bin_sensors_tpls[bin_sensor_id]: payload[KEY_VALUE_TEMPLATE] = lights_bin_sensors_tpls[bin_sensor_id] else: payload[KEY_PAYLOAD_ON] = lights_bin_sensors_pl[bin_sensor_id][VALUE_ON] payload[KEY_PAYLOAD_OFF] = lights_bin_sensors_pl[bin_sensor_id][ VALUE_OFF ] else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # color light sensors for sensor, sensor_options in light_sensors.items(): force_update = False if isinstance(device_config.get(CONF_FORCE_UPDATE_SENSORS), bool): force_update = device_config.get(CONF_FORCE_UPDATE_SENSORS) config_topic = ( f"{disc_prefix}/sensor/{dev_id}-color-{sensor}-{light_id}/config".encode( "ascii", "ignore" ).decode("utf-8") ) payload = { KEY_NAME: f"{device_name} {clean_name(sensor)} {light_id}", KEY_STATE_TOPIC: sensor_options[KEY_STATE_TOPIC].format(light_id=light_id), KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_FORCE_UPDATE: str(force_update).lower(), KEY_ENABLED_BY_DEFAULT: str(sensor_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-color-{sensor}-{light_id}".lower(), KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if sensor_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = sensor_options[KEY_ENTITY_CATEGORY] if sensor_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = sensor_options[KEY_DEVICE_CLASS] if sensor_options.get(KEY_STATE_CLASS): payload[KEY_STATE_CLASS] = sensor_options[KEY_STATE_CLASS] if sensor_options.get(KEY_UNIT): payload[KEY_UNIT] = sensor_options[KEY_UNIT] if sensor_options.get(KEY_VALUE_TEMPLATE): payload[KEY_VALUE_TEMPLATE] = sensor_options[KEY_VALUE_TEMPLATE] if sensor_options.get(ATTR_ICON): payload[KEY_ICON] = sensor_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" if mode == LIGHT_WHITE: payload = "" mqtt_publish(config_topic, payload, retain) # white lights for light_id, light_options in white_lights.items(): if device_config.get(f"light-{light_id}-name"): light_name = device_config[f"light-{light_id}-name"] else: light_name = f"{device_name} Light {light_id}" if model == MODEL_SHELLYRGBW2: unique_id = f"{dev_id}-light-white-{light_id}".lower() config_topic = f"{disc_prefix}/light/{dev_id}-white-{light_id}/config".encode( "ascii", "ignore" ).decode("utf-8") else: unique_id = f"{dev_id}-light-{light_id}".lower() config_topic = f"{disc_prefix}/light/{dev_id}-{light_id}/config".encode( "ascii", "ignore" ).decode("utf-8") payload = { KEY_SCHEMA: VALUE_TEMPLATE, KEY_NAME: light_name, KEY_COMMAND_TOPIC: light_options[KEY_COMMAND_TOPIC].format(light_id=light_id), KEY_STATE_TOPIC: light_options[KEY_STATE_TOPIC].format(light_id=light_id), KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_COMMAND_ON_TEMPLATE: light_options[KEY_COMMAND_ON_TEMPLATE].format( max_transition=MAX_TRANSITION ), KEY_COMMAND_OFF_TEMPLATE: f"{{^turn^:^off^{{%if transition is defined%}},^transition^:{{{{min(transition|multiply(1000),{MAX_TRANSITION})}}}}{{%endif%}}}}", KEY_STATE_TEMPLATE: "{%if value_json.ison%}on{%else%}off{%endif%}", KEY_BRIGHTNESS_TEMPLATE: "{{value_json.brightness|float|multiply(2.55)|round}}", KEY_UNIQUE_ID: unique_id, KEY_QOS: str(qos), KEY_DEVICE: device_info, "~": default_topic, } if light_options.get(KEY_COLOR_TEMP_TEMPLATE): payload[KEY_COLOR_TEMP_TEMPLATE] = TPL_COLOR_TEMP_WHITE_LIGHT if light_options.get(KEY_MAX_MIREDS): payload[KEY_MAX_MIREDS] = light_options[KEY_MAX_MIREDS] if light_options.get(KEY_MIN_MIREDS): payload[KEY_MIN_MIREDS] = light_options[KEY_MIN_MIREDS] if model == MODEL_SHELLYRGBW2 and mode == LIGHT_COLOR: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain, json=True) # white light's binary sensors for bin_sensor_id in range(len(lights_bin_sensors)): if ( lights_bin_sensors[bin_sensor_id] == SENSOR_INPUT and light_id == 0 ) or lights_bin_sensors[bin_sensor_id] != SENSOR_INPUT: unique_id = ( f"{dev_id}-white-{lights_bin_sensors[bin_sensor_id]}-{light_id}".lower() ) config_topic = f"{disc_prefix}/binary_sensor/{dev_id}-white-{lights_bin_sensors[bin_sensor_id]}-{light_id}/config".encode( "ascii", "ignore" ).decode( "utf-8" ) if lights_bin_sensors[bin_sensor_id] == SENSOR_INPUT: state_topic = f"~{lights_bin_sensors[bin_sensor_id]}/{light_id}" else: state_topic = f"~white/{light_id}/status" sensor_name = f"{device_name} {clean_name(lights_bin_sensors[bin_sensor_id])} {light_id}" if mode != LIGHT_COLOR: payload = { KEY_NAME: sensor_name, KEY_STATE_TOPIC: state_topic, KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_UNIQUE_ID: unique_id, KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if ( lights_bin_sensors_device_classes and lights_bin_sensors_device_classes[bin_sensor_id] ): payload[KEY_DEVICE_CLASS] = lights_bin_sensors_device_classes[ bin_sensor_id ] if lights_bin_sensors_tpls and lights_bin_sensors_tpls[bin_sensor_id]: payload[KEY_VALUE_TEMPLATE] = lights_bin_sensors_tpls[bin_sensor_id] else: payload[KEY_PAYLOAD_ON] = lights_bin_sensors_pl[bin_sensor_id][ VALUE_ON ] payload[KEY_PAYLOAD_OFF] = lights_bin_sensors_pl[bin_sensor_id][ VALUE_OFF ] else: payload = "" if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain) # white light sensors for sensor, sensor_options in light_sensors.items(): force_update = False if isinstance(device_config.get(CONF_FORCE_UPDATE_SENSORS), bool): force_update = device_config.get(CONF_FORCE_UPDATE_SENSORS) config_topic = ( f"{disc_prefix}/sensor/{dev_id}-white-{sensor}-{light_id}/config".encode( "ascii", "ignore" ).decode("utf-8") ) payload = { KEY_NAME: f"{device_name} {clean_name(sensor)} {light_id}", KEY_STATE_TOPIC: sensor_options[KEY_STATE_TOPIC].format(light_id=light_id), KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_FORCE_UPDATE: str(force_update).lower(), KEY_ENABLED_BY_DEFAULT: str(sensor_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-white-{sensor}-{light_id}".lower(), KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if sensor_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = sensor_options[KEY_ENTITY_CATEGORY] if sensor_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = sensor_options[KEY_DEVICE_CLASS] if sensor_options.get(KEY_STATE_CLASS): payload[KEY_STATE_CLASS] = sensor_options[KEY_STATE_CLASS] if sensor_options.get(KEY_UNIT): payload[KEY_UNIT] = sensor_options[KEY_UNIT] if sensor_options.get(KEY_VALUE_TEMPLATE): payload[KEY_VALUE_TEMPLATE] = sensor_options[KEY_VALUE_TEMPLATE] if sensor_options.get(ATTR_ICON): payload[KEY_ICON] = sensor_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" if mode == LIGHT_COLOR: payload = "" mqtt_publish(config_topic, payload, retain) # meter sensors for meter_id in range(meters): force_update = False if isinstance(device_config.get(CONF_FORCE_UPDATE_SENSORS), bool): force_update = device_config.get(CONF_FORCE_UPDATE_SENSORS) for sensor, sensor_options in meter_sensors.items(): config_topic = ( f"{disc_prefix}/sensor/{dev_id}-emeter-{sensor}-{meter_id}/config".encode( "ascii", "ignore" ).decode("utf-8") ) payload = { KEY_NAME: f"{device_name} {clean_name(sensor)} {meter_id}", KEY_STATE_TOPIC: sensor_options[KEY_STATE_TOPIC].format(meter_id=meter_id), KEY_AVAILABILITY_TOPIC: TOPIC_ONLINE, KEY_PAYLOAD_AVAILABLE: VALUE_TRUE, KEY_PAYLOAD_NOT_AVAILABLE: VALUE_FALSE, KEY_FORCE_UPDATE: str(force_update).lower(), KEY_ENABLED_BY_DEFAULT: str(sensor_options[KEY_ENABLED_BY_DEFAULT]).lower(), KEY_UNIQUE_ID: f"{dev_id}-emeter-{sensor}-{meter_id}".lower(), KEY_QOS: qos, KEY_DEVICE: device_info, "~": default_topic, } if sensor_options.get(KEY_ENTITY_CATEGORY): payload[KEY_ENTITY_CATEGORY] = sensor_options[KEY_ENTITY_CATEGORY] if sensor_options.get(KEY_DEVICE_CLASS): payload[KEY_DEVICE_CLASS] = sensor_options[KEY_DEVICE_CLASS] if sensor_options.get(KEY_STATE_CLASS): payload[KEY_STATE_CLASS] = sensor_options[KEY_STATE_CLASS] if sensor_options.get(KEY_UNIT): payload[KEY_UNIT] = sensor_options[KEY_UNIT] if sensor_options.get(KEY_VALUE_TEMPLATE): payload[KEY_VALUE_TEMPLATE] = sensor_options[KEY_VALUE_TEMPLATE] if sensor_options.get(ATTR_ICON): payload[KEY_ICON] = sensor_options[ATTR_ICON] if dev_id.lower() in ignored: payload = "" mqtt_publish(config_topic, payload, retain)