Esempio n. 1
0
    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()
Esempio n. 2
0
    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)
Esempio n. 4
0
    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()