"""MySensors constants for version 2.0 of MySensors.""" import voluptuous as vol from mysensors.const_15 import ( VALID_INTERNAL, VALID_SETREQ, VALID_STREAM, VALID_TYPES, BaseConst, MessageType, Stream, ) from mysensors.const_15 import MAX_NODE_ID # noqa: F401 from mysensors.validation import is_version from .handler import HANDLERS_20 def get_handler_registry(): """Return handler registry for this version.""" return HANDLERS_20 class Presentation(BaseConst): """MySensors presentation sub-types.""" S_DOOR = 0 # Door and window sensors S_MOTION = 1 # Motion sensors S_SMOKE = 2 # Smoke sensor S_BINARY = 3 # Binary device (on/off), Alias for S_LIGHT S_LIGHT = 3 # Light Actuator (on/off) S_DIMMER = 4 # Dimmable device of some kind S_COVER = 5 # Window covers or shades S_TEMP = 6 # Temperature sensor S_HUM = 7 # Humidity sensor S_BARO = 8 # Barometer sensor (Pressure) S_WIND = 9 # Wind sensor S_RAIN = 10 # Rain sensor S_UV = 11 # UV sensor S_WEIGHT = 12 # Weight sensor for scales etc. S_POWER = 13 # Power measuring device, like power meters S_HEATER = 14 # Heater device S_DISTANCE = 15 # Distance sensor S_LIGHT_LEVEL = 16 # Light sensor S_ARDUINO_NODE = 17 # Arduino node device S_ARDUINO_REPEATER_NODE = 18 # Arduino repeating node device S_ARDUINO_RELAY = 18 # Alias for compatability S_LOCK = 19 # Lock device S_IR = 20 # Ir sender/receiver device S_WATER = 21 # Water meter S_AIR_QUALITY = 22 # Air quality sensor e.g. MQ-2 S_CUSTOM = 23 # Use this for custom sensors S_DUST = 24 # Dust level sensor S_SCENE_CONTROLLER = 25 # Scene controller device S_RGB_LIGHT = 26 # RGB light # RGBW light (with separate white component) S_RGBW_LIGHT = 27 S_COLOR_SENSOR = 28 # Color sensor S_HVAC = 29 # Thermostat/HVAC device S_MULTIMETER = 30 # Multimeter device S_SPRINKLER = 31 # Sprinkler device S_WATER_LEAK = 32 # Water leak sensor S_SOUND = 33 # Sound sensor S_VIBRATION = 34 # Vibration sensor S_MOISTURE = 35 # Moisture sensor # LCD text device / Simple information device on controller, V_TEXT S_INFO = 36 S_GAS = 37 # Gas meter, V_FLOW, V_VOLUME S_GPS = 38 # GPS Sensor, V_POSITION S_WATER_QUALITY = 39 # V_TEMP, V_PH, V_ORP, V_EC, V_STATUS class SetReq(BaseConst): """MySensors set/req sub-types.""" V_TEMP = 0 # S_TEMP, S_HEATER, S_HVAC. Temperature. V_HUM = 1 # S_HUM. Humidity. # S_LIGHT, S_DIMMER, S_SPRINKLER, S_HVAC, S_HEATER. # Binary status, 0=off, 1=on. V_STATUS = 2 # Deprecated. Alias for V_STATUS. Light Status.0=off 1=on. V_LIGHT = 2 V_PERCENTAGE = 3 # S_DIMMER. Percentage value 0-100 (%). # Deprecated. Alias for V_PERCENTAGE. Dimmer value. 0-100 (%). V_DIMMER = 3 V_PRESSURE = 4 # S_BARO. Atmospheric Pressure. # S_BARO. Weather forecast. One of "stable", "sunny", "cloudy", "unstable", # "thunderstorm" or "unknown". V_FORECAST = 5 V_RAIN = 6 # S_RAIN. Amount of rain. V_RAINRATE = 7 # S_RAIN. Rate of rain. V_WIND = 8 # S_WIND. Wind speed. V_GUST = 9 # S_WIND. Gust. V_DIRECTION = 10 # S_WIND. Wind direction 0-360 (degrees). V_UV = 11 # S_UV. UV light level. V_WEIGHT = 12 # S_WEIGHT. Weight(for scales etc). V_DISTANCE = 13 # S_DISTANCE. Distance. V_IMPEDANCE = 14 # S_MULTIMETER, S_WEIGHT. Impedance value. # S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER. # Armed status of a security sensor. 1=Armed, 0=Bypassed. V_ARMED = 15 # S_DOOR, S_MOTION, S_SMOKE, S_SPRINKLER, S_WATER_LEAK, S_SOUND, # S_VIBRATION, S_MOISTURE. # Tripped status of a security sensor. 1=Tripped, 0=Untripped. V_TRIPPED = 16 # S_POWER, S_LIGHT, S_DIMMER, S_RGB_LIGHT, S_RGBW_LIGHT. # Watt value for power meters. V_WATT = 17 # S_POWER. Accumulated number of KWH for a power meter. V_KWH = 18 V_SCENE_ON = 19 # S_SCENE_CONTROLLER. Turn on a scene. V_SCENE_OFF = 20 # S_SCENE_CONTROLLER. Turn off a scene. # S_HEATER, S_HVAC. # Mode of heater. One of "Off", "HeatOn", "CoolOn", or "AutoChangeOver" V_HVAC_FLOW_STATE = 21 # S_HEATER, S_HVAC. HVAC/Heater fan speed ("Min", "Normal", "Max", "Auto") V_HVAC_SPEED = 22 # S_LIGHT_LEVEL. # Uncalibrated light level. 0-100%. Use V_LEVEL for light level in lux. V_LIGHT_LEVEL = 23 V_VAR1 = 24 # Custom value V_VAR2 = 25 # Custom value V_VAR3 = 26 # Custom value V_VAR4 = 27 # Custom value V_VAR5 = 28 # Custom value V_UP = 29 # S_COVER. Window covering. Up. V_DOWN = 30 # S_COVER. Window covering. Down. V_STOP = 31 # S_COVER. Window covering. Stop. V_IR_SEND = 32 # S_IR. Send out an IR-command. # S_IR. This message contains a received IR-command. V_IR_RECEIVE = 33 V_FLOW = 34 # S_WATER. Flow of water (in meter). V_VOLUME = 35 # S_WATER. Water volume. # S_LOCK. Set or get lock status. 1=Locked, 0=Unlocked. V_LOCK_STATUS = 36 # S_DUST, S_AIR_QUALITY, S_SOUND (dB), S_VIBRATION (hz), # S_LIGHT_LEVEL (lux). V_LEVEL = 37 V_DUST_LEVEL = 37 # Dust level V_VOLTAGE = 38 # S_MULTIMETER. Voltage level. V_CURRENT = 39 # S_MULTIMETER. Current level. # S_RGB_LIGHT, S_COLOR_SENSOR. # RGB value transmitted as ASCII hex string (I.e "ff0000" for red) V_RGB = 40 # S_RGBW_LIGHT. # RGBW value transmitted as ASCII hex string (I.e "ff0000ff" for red + # full white) V_RGBW = 41 # Optional unique sensor id (e.g. OneWire DS1820b ids) V_ID = 42 # S_TEMP. # S_DUST, S_AIR_QUALITY, S_DISTANCE. # Allows sensors to send in a string representing the unit prefix to be # displayed in GUI. # This is not parsed by controller! E.g. cm, m, km, inch. V_UNIT_PREFIX = 43 # S_HVAC. HVAC cool setpoint (Integer between 0-100). V_HVAC_SETPOINT_COOL = 44 # S_HEATER, S_HVAC. HVAC/Heater setpoint (Integer between 0-100). V_HVAC_SETPOINT_HEAT = 45 # S_HVAC. Flow mode for HVAC ("Auto", "ContinuousOn", "PeriodicOn"). V_HVAC_FLOW_MODE = 46 # S_INFO. Text message to display on LCD or controller device V_TEXT = 47 # S_CUSTOM. # Custom messages used for controller/inter node specific commands, # preferably using S_CUSTOM device type. V_CUSTOM = 48 # S_GPS. # GPS position and altitude. Payload: latitude;longitude;altitude(m). # E.g. "55.722526;13.017972;18" V_POSITION = 49 V_IR_RECORD = 50 # S_IR. Record IR codes for playback V_PH = 51 # S_WATER_QUALITY, water pH. # S_WATER_QUALITY, water ORP : redox potential in mV. V_ORP = 52 # S_WATER_QUALITY, water electric conductivity μS/cm (microSiemens/cm). V_EC = 53 V_VAR = 54 # S_POWER, Reactive power: volt-ampere reactive (var) V_VA = 55 # S_POWER, Apparent power: volt-ampere (VA) # S_POWER # Ratio of real power to apparent power. # Floating point value in the range [-1,..,1] V_POWER_FACTOR = 56 class Internal(BaseConst): """MySensors internal sub-types.""" # Use this to report the battery level (in percent 0-100). I_BATTERY_LEVEL = 0 # Sensors can request the current time from the Controller using this # message. The time will be reported as the seconds since 1970 I_TIME = 1 # Sensors report their library version at startup using this message type I_VERSION = 2 # Use this to request a unique node id from the controller. I_ID_REQUEST = 3 # Id response back to sensor. Payload contains sensor id. I_ID_RESPONSE = 4 # Start/stop inclusion mode of the Controller (1=start, 0=stop). I_INCLUSION_MODE = 5 # Config request from node. Reply with (M)etric or (I)mperal back to sensor I_CONFIG = 6 # When a sensor starts up, it broadcast a search request to all neighbor # nodes. They reply with a I_FIND_PARENT_RESPONSE. I_FIND_PARENT = 7 # Reply message type to I_FIND_PARENT request. I_FIND_PARENT_RESPONSE = 8 # Sent by the gateway to the Controller to trace-log a message I_LOG_MESSAGE = 9 # A message that can be used to transfer child sensors # (from EEPROM routing table) of a repeating node. I_CHILDREN = 10 # Optional sketch name that can be used to identify sensor in the # Controller GUI I_SKETCH_NAME = 11 # Optional sketch version that can be reported to keep track of the version # of sensor in the Controller GUI. I_SKETCH_VERSION = 12 # Used by OTA firmware updates. Request for node to reboot. I_REBOOT = 13 # Send by gateway to controller when startup is complete I_GATEWAY_READY = 14 # Provides signing related preferences (first byte is preference version). I_SIGNING_PRESENTATION = 15 I_REQUEST_SIGNING = 15 # alias from version 1.5 # Request for a nonce. I_NONCE_REQUEST = 16 I_GET_NONCE = 16 # alias from version 1.5 # Payload is nonce data. I_NONCE_RESPONSE = 17 I_GET_NONCE_RESPONSE = 17 # alias from version 1.5 I_HEARTBEAT = 18 I_PRESENTATION = 19 I_DISCOVER = 20 I_DISCOVER_RESPONSE = 21 I_HEARTBEAT_RESPONSE = 22 # Node is locked (reason in string-payload). I_LOCKED = 23 I_PING = 24 # Ping sent to node, payload incremental hop counter # In return to ping, sent back to sender, payload incremental hop counter I_PONG = 25 I_REGISTRATION_REQUEST = 26 # Register request to GW I_REGISTRATION_RESPONSE = 27 # Register response from GW I_DEBUG = 28 # Debug message VALID_MESSAGE_TYPES = { MessageType.presentation: list(Presentation), MessageType.set: list(SetReq), MessageType.req: list(SetReq), MessageType.internal: list(Internal), MessageType.stream: list(Stream), } VALID_PRESENTATION = {member: str for member in list(Presentation)} VALID_PRESENTATION.update( { Presentation.S_ARDUINO_NODE: is_version, Presentation.S_ARDUINO_REPEATER_NODE: is_version, Presentation.S_ARDUINO_RELAY: is_version, } ) VALID_TYPES = dict(VALID_TYPES) VALID_TYPES.update( { Presentation.S_POWER: [ SetReq.V_WATT, SetReq.V_KWH, SetReq.V_VAR, SetReq.V_VA, SetReq.V_POWER_FACTOR, SetReq.V_UNIT_PREFIX, ], Presentation.S_IR: [SetReq.V_IR_SEND, SetReq.V_IR_RECEIVE, SetReq.V_IR_RECORD], Presentation.S_CUSTOM: [ SetReq.V_VAR1, SetReq.V_VAR2, SetReq.V_VAR3, SetReq.V_VAR4, SetReq.V_VAR5, SetReq.V_CUSTOM, SetReq.V_UNIT_PREFIX, ], Presentation.S_INFO: [SetReq.V_TEXT], Presentation.S_GAS: [SetReq.V_FLOW, SetReq.V_VOLUME, SetReq.V_UNIT_PREFIX], Presentation.S_GPS: [SetReq.V_POSITION], Presentation.S_WATER_QUALITY: [ SetReq.V_TEMP, SetReq.V_PH, SetReq.V_ORP, SetReq.V_EC, SetReq.V_STATUS, SetReq.V_UNIT_PREFIX, ], } ) def validate_gps(value): """Validate GPS value.""" try: latitude, longitude, altitude = value.split(",") vol.Coerce(float)(latitude) vol.Coerce(float)(longitude) vol.Coerce(float)(altitude) except (TypeError, ValueError, vol.Invalid) as exc: raise vol.Invalid( 'GPS value should be of format "latitude,longitude,altitude"' ) from exc return value VALID_SETREQ = dict(VALID_SETREQ) VALID_SETREQ.update( { SetReq.V_TEXT: str, SetReq.V_CUSTOM: str, SetReq.V_POSITION: vol.All(str, validate_gps), SetReq.V_IR_RECORD: str, SetReq.V_PH: str, SetReq.V_ORP: str, SetReq.V_EC: str, SetReq.V_VAR: str, SetReq.V_VA: str, SetReq.V_POWER_FACTOR: vol.All( vol.Coerce(float), vol.Range(min=-1.0, max=1.0), vol.Coerce(str), msg="value should be between -1.0 and 1.0", ), } ) VALID_INTERNAL = dict(VALID_INTERNAL) VALID_INTERNAL.update( { Internal.I_HEARTBEAT: "", Internal.I_PRESENTATION: "", Internal.I_DISCOVER: "", Internal.I_DISCOVER_RESPONSE: vol.All( vol.Coerce(int), vol.Range(min=0, max=MAX_NODE_ID), vol.Coerce(str) ), Internal.I_HEARTBEAT_RESPONSE: vol.All(vol.Coerce(int), vol.Coerce(str)), Internal.I_LOCKED: str, Internal.I_PING: vol.All(vol.Coerce(int), vol.Coerce(str)), Internal.I_PONG: vol.All(vol.Coerce(int), vol.Coerce(str)), Internal.I_REGISTRATION_REQUEST: str, Internal.I_REGISTRATION_RESPONSE: str, Internal.I_DEBUG: str, } ) VALID_PAYLOADS = { MessageType.presentation: VALID_PRESENTATION, MessageType.set: VALID_SETREQ, MessageType.req: {member: "" for member in list(SetReq)}, MessageType.internal: VALID_INTERNAL, MessageType.stream: VALID_STREAM, }