def __init__(self, name, data): iot_devices.device.Device.__init__(self, name, data) self.devicesData = [] self.knownDevices = {} self.nameToType = {} self.nameToTopic = {} self.nameToZBInfo = {} self.nameToHandler = {} self.set_config_default("device.mqtt_server", 'localhost') self.set_config_default("device.friendly_name", '__all__') try: from scullery import mqtt #Ensure a new real connection. This makes sure we get any retained messages. self.connection = mqtt.getConnection( self.config['device.mqtt_server'], connectionID=str(time.time())) self.connection.subscribe('zigbee2mqtt/bridge/devices', self.onDevices) except Exception: self.handleException()
def __init__(self, channelKey, remoteNodeID=0, gateways=None, mqttServer="__virtual__SG1", mqttPort="default", localNodeID=None): self.bus = mqtt.getConnection(mqttServer, mqttPort) self.gateways = gateways or ['__all__'] self.key = channelKey # Default 0, disable node ID filtering self.nodeID = remoteNodeID self.localNodeID = localNodeID or 1 self.keepAwake = False self.lock = threading.RLock() self.rxMessageTimestamps = collections.OrderedDict() self.bus.subscribe("/SG1/i/" + b64(channelKey), self._onMessage, encoding="msgpack") self.bus.subscribe("/SG1/is/" + b64(channelKey), self._onStructuredMessage, encoding="msgpack") self.bus.subscribe("/SG1/ri/" + b64(channelKey), self._onRTMessage, encoding="msgpack") self.bus.subscribe("/SG1/b/" + b64(channelKey), self._onBeacon, encoding="msgpack") # This is how the gateway keeps track of what devices it's interested in. self.bus.subscribe("/SG1/discoverDevices", self._replyToDiscovery, encoding="msgpack") self.running = True # Tell any listening gateways that we exist self.bus.publish("/SG1/registerDevice/", self.key, encoding="msgpack") # Gateway, time, rssi, pathloss self.lastMessageInfo = (None, 0, -127, 127) self.StructuredMessageWriter = StructuredMessageWriter(self) self.writeStructured = self.StructuredMessageWriter.write self.flushStructured = self.StructuredMessageWriter.flush
def Connection(server, port=1883, password=None, alertPriority="info", alertAck=True, messageBusName=None, connectionID=None): from src import mqtt as mqttPatch from scullery import mqtt return mqtt.getConnection(server=server, port=port, password=password, alertPriority=alertPriority, alertAck=alertAck, messageBusName=messageBusName, connectionID=connectionID)
def __init__(self, port, id="default", mqttServer="__virtual__SG1", mqttPort="default", channelNumber=3, rfProfile=7): self.bus = mqtt.getConnection(mqttServer, mqttPort) self.lock = threading.RLock() # Used for matching requests to responses. self.reqID = 0 self.reqsAwaiting = {} self.port = port self.gwid = id self.currentProfile = rfProfile self.currentChannel = channelNumber self.lastMessageSentPerChannelKey = collections.OrderedDict() self.running = True self.parser = NanoframeParser(self.onHWMessage, self) self.connected = False self.lastDidDiscovery = 0 self.lastSentTime = 0 self.lastSerConnectAttempt = -9999999999 self.thread = threading.Thread(target=makeThreadFunction( weakref.ref(self)), daemon=True) try: self.thread.name = "SG1Thread" except: pass self.waitingTypes = {} self.portObj = None self.portRetryTimes = {} self.reqIDCounter = int(random.random() * 255) self.connect() # Devices that have been discovered via the bus, plus their # last announce timestamp self.discoveredDevices = {} self.hintlookup = HintLookup() self.lastPrintedErr = 0 self.thread.start() try: self.sync() except Exception: logger.exception("Error connecting to SG1 Gateway at: " + str(port) + ",retrying later") self.lastSentTime = 0 self.waitOnSyncLock = threading.Lock() self.currentKey = b'\0' * 32 self.currentProfile = rfProfile self.currentChannel = channelNumber # Indexed by channel key, ordered by timestamp, wake requests expire after # 30 seconds. Only change this list under lock. self.wakeRequests = {} # Now do the bus subscriptions self.bus.subscribe("/SG1/wake/" + self.gwid, self.onWakeRequest, encoding="msgpack") self.bus.subscribe("/SG1/send/" + self.gwid, self.onSendRequest, encoding="msgpack") self.bus.subscribe("/SG1/wake/" + self.gwid, self.onWakeRequest, encoding="msgpack") self.bus.subscribe("/SG1/send/" + "__all__", self.onSendRequest, encoding="msgpack") self.bus.subscribe("/SG1/pair/" + self.gwid, self.onDeviceRequestPair, encoding="msgpack") self.bus.subscribe("/SG1/wake/" + "__all__", self.onWakeRequest, encoding="msgpack") self.bus.subscribe("/SG1/registerDevice/", self.handleAnnounce, encoding="msgpack")
def __init__(self, name, data): devices.Device.__init__(self, name, data) try: self.set_config_default('device.interval', '300') self.numeric_data_point( "rssi", min=-180, max=12, interval=float(self.config["device.interval"]), description= "-75 if recetly seen, otherwise -180, we don't have real RSSI data", writable=False) self.set_alarm("No Signal", 'rssi', "value<-110") self.set_config_default('device.id', '') self.set_config_default('device.model', '') self.set_config_default('device.server', 'localhost') self.set_config_default('device.port', '1883') self.set_config_default('device.password', '') self.set_config_default('device.mqttTopic', 'home/rtl_433') # Pretend we have seen it to give the checker the right interval # before declaring it lost self.lastseen = time.monotonic() # This connection is actually possibly shared # Scullery does the deduplication for us self.connection = mqtt.getConnection( self.config["device.server"], int(self.config["device.port"].strip() or 1883), password=self.config["device.password"].strip(), connectionID=str("RTL433Connection")) self.numeric_data_point("mqttStatus", writable=False) self.connection.subscribeToStatus(self.onConnectionChange) self.set_data_point("mqttStatus", 1 if self.connection.isConnected else 0) self.set_alarm("MQTT Lost", "mqttStatus", "value < 0.5", auto_ack=True) topic = data.get("device.mqtttopic", "home/rtl_433") # We cannot use priority greater than info because these are unencrypted and untruusted and higher could make noise. def onBattery(t, m): m = float(m) if not 'battery' in self.datapoints: self.numeric_data_point("battery", default=50, writable=False, unit="%") # Always set before setting the alarm. self.set_data_point("battery", m) self.set_alarm(name="Low battery", datapoint="battery", expression="value < 15", priority="info", auto_ack=True) self.set_data_point("battery", m) def onWind(t, m): m = float(m) if not 'wind' in self.datapoints: self.numeric_data_point("wind", unit="km/h", writable=False) self.set_alarm(name="High Wind", datapoint="wind", expression="value > 35", priority="info") self.set_data_point("wind", m) def onTemp(t, m): m = float(m) if not 'temp' in self.datapoints: self.numeric_data_point("temp", unit="degC", writable=False) self.set_alarm(name="Freezing temperatures", datapoint="temp", expression="value < 2", priority="info") self.set_data_point("temp", m) def onHum(t, m): m = float(m) if not 'humidity' in self.datapoints: self.numeric_data_point("humidity", unit="%", writable=False) self.set_alarm(name="High humidity", datapoint="humidity", expression="value > 80", priority="info") self.set_alarm(name="Low humidity", datapoint="humidity", expression="value < 20", priority="info", auto_ack=True) self.set_data_point("humidity", m) def onMoist(t, m): m = float(m) if not 'moisture' in self.datapoints: self.numeric_data_point("moisture", unit="%", writable=False) self.set_data_point("moisture", m) def onPres(t, m): m = float(m) if not 'pressure' in self.datapoints: self.numeric_data_point("pressure", unit="Pa", writable=False) self.set_data_point("pressure", m) def onWeight(t, m): m = float(m) if not 'weight' in self.datapoints: self.numeric_data_point("weight", writable=False) self.set_data_point("weight", m) def onCommandCode(t, m): m = float(m) if not 'lastCommandCode' in self.datapoints: self.object_data_point("lastCommandCode", writable=False) self.set_data_point("lastCommandCode", (m, time.time())) def onCommandName(t, m): m = float(m) if not 'lastCommandName' in self.datapoints: self.object_data_point("lastCommandName", writable=False) self.set_data_point("lastCommandName", (m, time.time())) def onJSON(t, m): try: m = json.loads(m) self.print(m, "Saw packet on air") # Going to do an ID match. if 'device.id' in self.config and self.config['device.id']: if not ('id' in m and str(m['id']) == self.config['device.id']): self.print(m, "Packet filter miss") return if 'device.model' in self.config and self.config[ 'device.id']: if not ('model' in m and m['model'] == self.config['device.model']): self.print(m, "Packet filter miss") return self.print(m, "Packet filter hit") # No real RSSI, we just use -75 to mean good and -180 to mean bad. self.set_data_point("rssi", -75) self.set_alarm("Signal Lost", "rssi", "value < -98", auto_ack=True) self.lastSeen = time.monotonic() if 'humidity' in m: onHum(0, m['humidity']) if 'moisture' in m: onMoist(0, m['moisture']) if 'temperature_C' in m: onTemp(0, m['temperature_C']) if 'wind_avg_km_h' in m: onWind(0, m['wind_avg_km_h']) if 'pressure_kPa' in m: onPres(0, m['pressure_kPa'] * 1000) if 'pressure_hPa' in m: onPres(0, m['pressure_hPa'] * 100) # Keep a percent based API with randomly chosen high and low numbers if 'battery_ok' in m: onBattery(0, 100 if m['battery_ok'] else 5) if 'cmd' in m: onCommandCode(0, m['cmd']) if 'button_id' in m: onCommandCode(0, m['button_id']) if 'button_name' in m: onCommandName(0, m['button_name']) if 'event' in m: onCommandName(0, m['event']) if 'code' in m: onCommandCode(0, m['code']) except: self.handle_exception() self.noGarbage = [onJSON] self.connection.subscribe(topic, onJSON, encoding="raw") all_devs[self.name] = self except Exception: self.handle_exception()