def __init__(self, hass, name, state_topic, command_topic, qos, payload_disarm, payload_arm_home, payload_arm_away, code): """Initalize the MQTT alarm panel.""" self._state = STATE_UNKNOWN self._hass = hass self._name = name self._state_topic = state_topic self._command_topic = command_topic self._qos = qos self._payload_disarm = payload_disarm self._payload_arm_home = payload_arm_home self._payload_arm_away = payload_arm_away self._code = code def message_received(topic, payload, qos): """A new MQTT message has been received.""" if payload not in (STATE_ALARM_DISARMED, STATE_ALARM_ARMED_HOME, STATE_ALARM_ARMED_AWAY, STATE_ALARM_PENDING, STATE_ALARM_TRIGGERED): _LOGGER.warning('Received unexpected payload: %s', payload) return self._state = payload self.update_ha_state() mqtt.subscribe(hass, self._state_topic, message_received, self._qos)
def __init__(self, hass, name, state_topic, command_topic, qos, payload_up, payload_down, payload_stop, value_template): """Initialize the roller shutter.""" self._state = None self._hass = hass self._name = name self._state_topic = state_topic self._command_topic = command_topic self._qos = qos self._payload_up = payload_up self._payload_down = payload_down self._payload_stop = payload_stop if self._state_topic is None: return def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: payload = template.render_with_possible_json_value( hass, value_template, payload) if payload.isnumeric() and 0 <= int(payload) <= 100: self._state = int(payload) self.update_ha_state() else: _LOGGER.warning( "Payload is expected to be an integer between 0 and 100") mqtt.subscribe(hass, self._state_topic, message_received, self._qos)
def __init__(self, hass, name, state_topic, command_topic, qos, retain, state_open, state_closed, service_open, service_close, optimistic, value_template): """Initialize the garage door.""" self._hass = hass self._name = name self._state_topic = state_topic self._command_topic = command_topic self._qos = qos self._retain = retain self._state_open = state_open self._state_closed = state_closed self._service_open = service_open self._service_close = service_close self._optimistic = optimistic or state_topic is None self._state = False def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: payload = template.render_with_possible_json_value( hass, value_template, payload) if payload == self._state_open: self._state = True self.update_ha_state() elif payload == self._state_closed: self._state = False self.update_ha_state() if self._state_topic is None: # Force into optimistic mode. self._optimistic = True else: mqtt.subscribe(hass, self._state_topic, message_received, self._qos)
def __init__(self, hass, name, state_topic, command_topic, qos, retain, payload_on, payload_off, optimistic, value_template): """Initialize the MQTT switch.""" self._state = False self._hass = hass self._name = name self._state_topic = state_topic self._command_topic = command_topic self._qos = qos self._retain = retain self._payload_on = payload_on self._payload_off = payload_off self._optimistic = optimistic def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: payload = template.render_with_possible_json_value( hass, value_template, payload) if payload == self._payload_on: self._state = True self.update_ha_state() elif payload == self._payload_off: self._state = False self.update_ha_state() if self._state_topic is None: # Force into optimistic mode. self._optimistic = True else: mqtt.subscribe(hass, self._state_topic, message_received, self._qos)
def __init__(self, hass, name, state_topic, sensor_class, qos, payload_on, payload_off, value_template): """Initialize the MQTT binary sensor.""" self._hass = hass self._name = name self._state = False self._state_topic = state_topic self._sensor_class = sensor_class self._payload_on = payload_on self._payload_off = payload_off self._qos = qos def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: payload = template.render_with_possible_json_value( hass, value_template, payload) if payload == self._payload_on: self._state = True self.update_ha_state() elif payload == self._payload_off: self._state = False self.update_ha_state() mqtt.subscribe(hass, self._state_topic, message_received, self._qos)
def test_subscribe_topic_subtree_wildcard_no_match(self): """Test the subscription of wildcard topics.""" mqtt.subscribe(self.hass, 'test-topic/#', self.record_calls) fire_mqtt_message(self.hass, 'another-test-topic', 'test-payload') self.hass.pool.block_till_done() self.assertEqual(0, len(self.calls))
def test_subscribe_topic_not_match(self): """Test if subscribed topic is not a match.""" mqtt.subscribe(self.hass, 'test-topic', self.record_calls) fire_mqtt_message(self.hass, 'another-test-topic', 'test-payload') self.hass.pool.block_till_done() self.assertEqual(0, len(self.calls))
def test_subscribe_topic_subtree_wildcard_root_topic(self): """Test the subscription of wildcard topics.""" mqtt.subscribe(self.hass, 'test-topic/#', self.record_calls) fire_mqtt_message(self.hass, 'test-topic', 'test-payload') self.hass.pool.block_till_done() self.assertEqual(1, len(self.calls)) self.assertEqual('test-topic', self.calls[0][0]) self.assertEqual('test-payload', self.calls[0][1])
def setup_scanner(hass, config, see): """Setup the MQTT tracker.""" devices = config[CONF_DEVICES] qos = config[CONF_QOS] dev_id_lookup = {} def device_tracker_message_received(topic, payload, qos): """MQTT message received.""" see(dev_id=dev_id_lookup[topic], location_name=payload) for dev_id, topic in devices.items(): dev_id_lookup[topic] = dev_id mqtt.subscribe(hass, topic, device_tracker_message_received, qos) return True
def __init__(self, hass, name, state_topic, qos, unit_of_measurement, value_template): """Initialize the sensor.""" self._state = STATE_UNKNOWN self._hass = hass self._name = name self._state_topic = state_topic self._qos = qos self._unit_of_measurement = unit_of_measurement def message_received(topic, payload, qos): """A new MQTT message has been received.""" if value_template is not None: payload = template.render_with_possible_json_value( hass, value_template, payload) self._state = payload self.update_ha_state() mqtt.subscribe(hass, self._state_topic, message_received, self._qos)
def trigger(hass, config, action): """Listen for state changes based on configuration.""" topic = config[CONF_TOPIC] payload = config.get(CONF_PAYLOAD) def mqtt_automation_listener(msg_topic, msg_payload, qos): """Listen for MQTT messages.""" if payload is None or payload == msg_payload: action({ 'trigger': { 'platform': 'mqtt', 'topic': msg_topic, 'payload': msg_payload, 'qos': qos, } }) mqtt.subscribe(hass, topic, mqtt_automation_listener) return True
def setup_scanner(hass, config, see): """Setup an OwnTracks tracker.""" max_gps_accuracy = config.get(CONF_MAX_GPS_ACCURACY) def validate_payload(payload, data_type): """Validate OwnTracks payload.""" try: data = json.loads(payload) except ValueError: # If invalid JSON _LOGGER.error('Unable to parse payload as JSON: %s', payload) return None if not isinstance(data, dict) or data.get('_type') != data_type: _LOGGER.debug('Skipping %s update for following data ' 'because of missing or malformatted data: %s', data_type, data) return None if max_gps_accuracy is not None and \ convert(data.get('acc'), float, 0.0) > max_gps_accuracy: _LOGGER.debug('Skipping %s update because expected GPS ' 'accuracy %s is not met: %s', data_type, max_gps_accuracy, data) return None if convert(data.get('acc'), float, 1.0) == 0.0: _LOGGER.debug('Skipping %s update because GPS accuracy' 'is zero', data_type) return None return data def owntracks_location_update(topic, payload, qos): """MQTT message received.""" # Docs on available data: # http://owntracks.org/booklet/tech/json/#_typelocation data = validate_payload(payload, 'location') if not data: return dev_id, kwargs = _parse_see_args(topic, data) # Block updates if we're in a region with LOCK: if REGIONS_ENTERED[dev_id]: _LOGGER.debug( "location update ignored - inside region %s", REGIONS_ENTERED[-1]) return see(**kwargs) see_beacons(dev_id, kwargs) def owntracks_event_update(topic, payload, qos): """MQTT event (geofences) received.""" # Docs on available data: # http://owntracks.org/booklet/tech/json/#_typetransition data = validate_payload(payload, 'transition') if not data: return if data.get('desc') is None: _LOGGER.error( "Location missing from `Entering/Leaving` message - " "please turn `Share` on in OwnTracks app") return # OwnTracks uses - at the start of a beacon zone # to switch on 'hold mode' - ignore this location = slugify(data['desc'].lstrip("-")) if location.lower() == 'home': location = STATE_HOME dev_id, kwargs = _parse_see_args(topic, data) def enter_event(): """Execute enter event.""" zone = hass.states.get("zone.{}".format(location)) with LOCK: if zone is None and data.get('t') == 'b': # Not a HA zone, and a beacon so assume mobile beacons = MOBILE_BEACONS_ACTIVE[dev_id] if location not in beacons: beacons.append(location) _LOGGER.info("Added beacon %s", location) else: # Normal region regions = REGIONS_ENTERED[dev_id] if location not in regions: regions.append(location) _LOGGER.info("Enter region %s", location) _set_gps_from_zone(kwargs, location, zone) see(**kwargs) see_beacons(dev_id, kwargs) def leave_event(): """Execute leave event.""" with LOCK: regions = REGIONS_ENTERED[dev_id] if location in regions: regions.remove(location) new_region = regions[-1] if regions else None if new_region: # Exit to previous region zone = hass.states.get("zone.{}".format(new_region)) _set_gps_from_zone(kwargs, new_region, zone) _LOGGER.info("Exit to %s", new_region) see(**kwargs) see_beacons(dev_id, kwargs) else: _LOGGER.info("Exit to GPS") # Check for GPS accuracy if not ('acc' in data and max_gps_accuracy is not None and data['acc'] > max_gps_accuracy): see(**kwargs) see_beacons(dev_id, kwargs) else: _LOGGER.info("Inaccurate GPS reported") beacons = MOBILE_BEACONS_ACTIVE[dev_id] if location in beacons: beacons.remove(location) _LOGGER.info("Remove beacon %s", location) if data['event'] == 'enter': enter_event() elif data['event'] == 'leave': leave_event() else: _LOGGER.error( 'Misformatted mqtt msgs, _type=transition, event=%s', data['event']) return def see_beacons(dev_id, kwargs_param): """Set active beacons to the current location.""" kwargs = kwargs_param.copy() # the battery state applies to the tracking device, not the beacon kwargs.pop('battery', None) for beacon in MOBILE_BEACONS_ACTIVE[dev_id]: kwargs['dev_id'] = "{}_{}".format(BEACON_DEV_ID, beacon) kwargs['host_name'] = beacon see(**kwargs) mqtt.subscribe(hass, LOCATION_TOPIC, owntracks_location_update, 1) mqtt.subscribe(hass, EVENT_TOPIC, owntracks_event_update, 1) return True
def __init__(self, hass, name, topic, templates, qos, retain, payload, optimistic, brightness_scale): """Initialize MQTT light.""" self._hass = hass self._name = name self._topic = topic self._qos = qos self._retain = retain self._payload = payload self._optimistic = optimistic or topic["state_topic"] is None self._optimistic_rgb = optimistic or topic["rgb_state_topic"] is None self._optimistic_brightness = (optimistic or topic["brightness_state_topic"] is None) self._brightness_scale = brightness_scale self._state = False templates = {key: ((lambda value: value) if tpl is None else partial(render_with_possible_json_value, hass, tpl)) for key, tpl in templates.items()} def state_received(topic, payload, qos): """A new MQTT message has been received.""" payload = templates['state'](payload) if payload == self._payload["on"]: self._state = True elif payload == self._payload["off"]: self._state = False self.update_ha_state() if self._topic["state_topic"] is not None: mqtt.subscribe(self._hass, self._topic["state_topic"], state_received, self._qos) def brightness_received(topic, payload, qos): """A new MQTT message for the brightness has been received.""" device_value = float(templates['brightness'](payload)) percent_bright = device_value / self._brightness_scale self._brightness = int(percent_bright * 255) self.update_ha_state() if self._topic["brightness_state_topic"] is not None: mqtt.subscribe(self._hass, self._topic["brightness_state_topic"], brightness_received, self._qos) self._brightness = 255 elif self._topic["brightness_command_topic"] is not None: self._brightness = 255 else: self._brightness = None def rgb_received(topic, payload, qos): """A new MQTT message has been received.""" self._rgb = [int(val) for val in templates['rgb'](payload).split(',')] self.update_ha_state() if self._topic["rgb_state_topic"] is not None: mqtt.subscribe(self._hass, self._topic["rgb_state_topic"], rgb_received, self._qos) self._rgb = [255, 255, 255] if self._topic["rgb_command_topic"] is not None: self._rgb = [255, 255, 255] else: self._rgb = None
def setup_scanner(hass, config, see): """Setup an OwnTracks tracker.""" max_gps_accuracy = config.get(CONF_MAX_GPS_ACCURACY) def validate_payload(payload, data_type): """Validate OwnTracks payload.""" try: data = json.loads(payload) except ValueError: # If invalid JSON _LOGGER.error('Unable to parse payload as JSON: %s', payload) return None if not isinstance(data, dict) or data.get('_type') != data_type: _LOGGER.debug( 'Skipping %s update for following data ' 'because of missing or malformatted data: %s', data_type, data) return None if max_gps_accuracy is not None and \ convert(data.get('acc'), float, 0.0) > max_gps_accuracy: _LOGGER.debug( 'Skipping %s update because expected GPS ' 'accuracy %s is not met: %s', data_type, max_gps_accuracy, data) return None if convert(data.get('acc'), float, 1.0) == 0.0: _LOGGER.debug('Skipping %s update because GPS accuracy' 'is zero', data_type) return None return data def owntracks_location_update(topic, payload, qos): """MQTT message received.""" # Docs on available data: # http://owntracks.org/booklet/tech/json/#_typelocation data = validate_payload(payload, 'location') if not data: return dev_id, kwargs = _parse_see_args(topic, data) # Block updates if we're in a region with LOCK: if REGIONS_ENTERED[dev_id]: _LOGGER.debug("location update ignored - inside region %s", REGIONS_ENTERED[-1]) return see(**kwargs) see_beacons(dev_id, kwargs) def owntracks_event_update(topic, payload, qos): """MQTT event (geofences) received.""" # Docs on available data: # http://owntracks.org/booklet/tech/json/#_typetransition data = validate_payload(payload, 'transition') if not data: return if data.get('desc') is None: _LOGGER.error("Location missing from `Entering/Leaving` message - " "please turn `Share` on in OwnTracks app") return # OwnTracks uses - at the start of a beacon zone # to switch on 'hold mode' - ignore this location = slugify(data['desc'].lstrip("-")) if location.lower() == 'home': location = STATE_HOME dev_id, kwargs = _parse_see_args(topic, data) def enter_event(): """Execute enter event.""" zone = hass.states.get("zone.{}".format(location)) with LOCK: if zone is None and data.get('t') == 'b': # Not a HA zone, and a beacon so assume mobile beacons = MOBILE_BEACONS_ACTIVE[dev_id] if location not in beacons: beacons.append(location) _LOGGER.info("Added beacon %s", location) else: # Normal region regions = REGIONS_ENTERED[dev_id] if location not in regions: regions.append(location) _LOGGER.info("Enter region %s", location) _set_gps_from_zone(kwargs, location, zone) see(**kwargs) see_beacons(dev_id, kwargs) def leave_event(): """Execute leave event.""" with LOCK: regions = REGIONS_ENTERED[dev_id] if location in regions: regions.remove(location) new_region = regions[-1] if regions else None if new_region: # Exit to previous region zone = hass.states.get("zone.{}".format(new_region)) _set_gps_from_zone(kwargs, new_region, zone) _LOGGER.info("Exit to %s", new_region) see(**kwargs) see_beacons(dev_id, kwargs) else: _LOGGER.info("Exit to GPS") # Check for GPS accuracy if not ('acc' in data and max_gps_accuracy is not None and data['acc'] > max_gps_accuracy): see(**kwargs) see_beacons(dev_id, kwargs) else: _LOGGER.info("Inaccurate GPS reported") beacons = MOBILE_BEACONS_ACTIVE[dev_id] if location in beacons: beacons.remove(location) _LOGGER.info("Remove beacon %s", location) if data['event'] == 'enter': enter_event() elif data['event'] == 'leave': leave_event() else: _LOGGER.error('Misformatted mqtt msgs, _type=transition, event=%s', data['event']) return def see_beacons(dev_id, kwargs_param): """Set active beacons to the current location.""" kwargs = kwargs_param.copy() # the battery state applies to the tracking device, not the beacon kwargs.pop('battery', None) for beacon in MOBILE_BEACONS_ACTIVE[dev_id]: kwargs['dev_id'] = "{}_{}".format(BEACON_DEV_ID, beacon) kwargs['host_name'] = beacon see(**kwargs) mqtt.subscribe(hass, LOCATION_TOPIC, owntracks_location_update, 1) mqtt.subscribe(hass, EVENT_TOPIC, owntracks_event_update, 1) return True