Ejemplo n.º 1
0
class NEC_IR():
    edgecount = 68
    block_time = 73  # 68.1ms nominal. Allow for some tx tolerance (?)

    def __init__(self, pin, callback):
        self._ev_start = Event()
        self._callback = callback
        self._times = array(
            'i', (0 for _ in range(self.edgecount + 1)))  # 1 for overrun
        ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin)
        self._reset()
        loop = asyncio.get_event_loop()
        loop.create_task(self._run())

    def _reset(self):
        self._edge = 0
        self._overrun = False
        self._ev_start.clear()

    async def _run(self):
        while True:
            await self._ev_start  # Wait unitl data collection has started
            await asyncio.sleep_ms(self.block_time
                                   )  # Data block should have ended
            self._decode()  # decode, clear event, prepare for new rx, call cb

    # Pin interrupt. Save time of each edge for later decode.
    def _cb_pin(self, line):
        if not self._overrun:  # Overrun: ignore pulses until software timer times out
            if not self._ev_start.is_set():  # First edge received
                self._ev_start.set()
            self._times[self._edge] = ticks_us()
            if self._edge < self.edgecount:
                self._edge += 1
            else:
                self._overrun = True  # Overrun. decode() will test and reset

    def _decode(self):
        val = -3 if self._overrun else 0
        if not self._overrun:
            width = ticks_diff(self._times[1], self._times[0])
            if width > 4000:  # 9ms leading mark for all valid data
                width = ticks_diff(self._times[2], self._times[1])
                if width > 3000:  # 4.5ms space for normal data
                    if self._edge < self.edgecount:
                        val = -1  # Haven't received the correct number of edges
                    else:  # Time spaces only (marks are identical)
                        for edge_no in range(3, self.edgecount, 2):
                            val &= 0x1fffffff  # Constrain to 32 bit integer (b30 == b31)
                            val <<= 1  # nos. will still be unique because of logical inverse address
                            width = ticks_diff(self._times[edge_no + 1],
                                               self._times[edge_no])
                            if width > 1120:
                                val += 1
                elif width > 1700:  # 2.5ms space for a repeat code. Should have exactly 4 edges.
                    val = 1 if self._edge == 4 else -2
        self._reset()
        self._callback(val)
Ejemplo n.º 2
0
class LED_Flashable():
    def __init__(self, loop, led_no):
        self.led = pyb.LED(led_no)
        self.event = Event()
        loop.create_task(self.flash_task())

    def flash(self, period_ms):
        if self.event.is_set():
            return
        self.event.set(period_ms)

    async def flash_task(self):
        while True:
            await self.event
            period_ms = self.event.value()
            self.event.clear()
            self.led.on()
            await asyncio.sleep_ms(period_ms)
            self.led.off()
Ejemplo n.º 3
0
async def run_ack():
    loop = asyncio.get_event_loop()
    event = Event()
    ack1 = Event()
    ack2 = Event()
    count = 0
    while True:
        loop.create_task(event_wait(event, ack1, 1))
        loop.create_task(event_wait(event, ack2, 2))
        event.set(count)
        count += 1
        print('event was set')
        await ack1
        ack1.clear()
        print('Cleared ack1')
        await ack2
        ack2.clear()
        print('Cleared ack2')
        event.clear()
        print('Cleared event')
        await asyncio.sleep(1)
Ejemplo n.º 4
0
class ds18_plugin:
    valuenames          = {}
    datastore           = None
    roms                = None
    
    def __init__(self) :
        # generic section
        self._log       = core._log
        self._log.debug("Plugin: ds18 contruction")
        self._utils     = core._utils
        self._plugins   = core._plugins
        self._hal       = core._hal
        self._lock      = Event()
        # plugin specific section
        self.dxpin      = dxpin
        self.valuenames["valueN1"]= "Temperature"
        self.valuenames["valueF1"]= ""
        self.valuenames["valueD1"]= 0
        # release lock, ready for next measurement
        self._lock.clear()
        
    def init(self, plugin, device, queue, scriptqueue):        
        self._log.debug("Plugin: ds18 init")
        # generic section
        self._utils.plugin_initdata(self, plugin, device, queue, scriptqueue)
        self.pincnt             = pincnt
        self.valuecnt           = valuecnt
        self.stype              = stype
        self.content            = plugin.get('content',content)
        self.dxpin              = device.get('dxpin',dxpin)
        self._log.debug("Plugin: ds18 init dxpin"+self.dxpin)
        self.valuenames['devicename'] = device['name'] # gets device/plugin name, added AJ
        plugin['dtype']         = dtype
        plugin['stype']         = stype
        plugin['template']      = template
        datastore               = self._plugins.readstore(device["name"])
        # plugin specific section
        self._log.debug("Plugin: ds18 init, pin used: "+str(self.dxpin))
        # the device is on Dx
        self.mPin                   = self._hal.pin(self.dxpin)
        if self.mPin:
            # create the onewire object
            self.ds18                   = ds18x20.DS18X20(onewire.OneWire(self.mPin))
            # scan for devices on the bus
            roms                        = self.ds18.scan()
            # scan for devices on the bus
            self.roms                   = self.ds18.scan()

        return True

    def loadform(self,plugindata):
        self._log.debug("Plugin: ds18 loadform")
        # generic section
        self._utils.plugin_loadform(self, plugindata)
        # plugin specific section
        plugindata['resolution']= resolution
        romcnt = 0
        if not self.roms == None:
            for rom in self.roms:
                plugindata['rom'+str(romcnt)] = ''.join('{:02x}-'.format(x) for x in rom)[:-1]
                self._log.debug("Plugin: ds18 loadform, rom: "+plugindata['rom'+str(romcnt)])
                romcnt+=1
        else:
            self._log.debug("Plugin: ds18 loadform, no roms!")
        plugindata['romcnt']    = romcnt
        
    def saveform(self,plugindata):
        self._log.debug("Plugin: ds18 saveform")
        # generic section
        self._utils.plugin_saveform(self, plugindata)

        # plugin specific section
        self.romid                  = plugindata.get('deviceid','')
        self.resolution             = plugindata['resolution']

        # store values
        data = {}
        data["romid"]       = self.romid
        data["dxpin"]       = self.dxpin
        data["resolution"]  = self.resolution
        data["valueN1"]     = self.valuenames["valueN1"]
        data["valueF1"]     = self.valuenames["valueF1"] 
        data["valueD1"]     = self.valuenames["valueD1"]
        self._plugins.writestore(self.devicename, data)

        # the device is on Dx
        self.mPin                   = self._hal.pin(self.dxpin)
        self._log.debug("Plugin: ds18 saveform, pin used: "+str(self.dxpin))
        # create the onewire object
        self.ds18                   = ds18x20.DS18X20(onewire.OneWire(self.mPin))
        # scan for devices on the bus
        roms                        = self.ds18.scan()
        # scan for devices on the bus
        self.roms                   = self.ds18.scan()
        
    def read(self, values):
        self._log.debug("Plugin: ds18 read")
        # plugin specific section
        if not self.roms == None:
            for rom in self.roms:
                # Set convert on
                self.ds18.convert_temp()
                # wait 750ms for value to return
                #await asyncio.sleep_ms(750)
                import utime
                utime.sleep_ms(750)
                # Read temp
                values['valueN1'] = ''.join('{:02x}-'.format(x) for x in rom)[:-1]
                values["valueV1"] = round(self.ds18.read_temp(rom), int(self.valuenames['valueD1']) )
        else:
            self._log.debug("Plugin: ds18 read, empty values")
            # dummy values
            values['valueN1'] = ''
            values["valueV1"] = ''
   
    def write(self, values):
        self._log.debug("Plugin: ds18 write")

    async def asyncprocess(self):
        self._log.debug("Plugin: ds18 process")
        # plugin specific section
        if not self.roms == None:
            for rom in self.roms:
                # Set convert on
                self.ds18.convert_temp()
                # wait 750ms for value to return
                await asyncio.sleep_ms(750)
                # put temperature value(s) in queue
                try:
                    ds18temp = self.ds18.read_temp(rom)
                    self._log.debug("Plugin: ds18 data read: "+str(ds18temp))
                    # send data to protocol and script/rule queues
                    #self.valuenames["valueV1"] = ds18temp        
                    self.valuenames['valueV1'] = round(ds18temp, int(self.valuenames['valueD1']) )
                    self._utils.plugin_senddata(self)
                except Exception as e:
                    self._log.debug("Plugin: ds18 readtemp failed! Error: "+repr(e))
        # release lock, ready for next measurement
        self._lock.clear()
Ejemplo n.º 5
0
class openhab_mqtt_protocol:
    processcnt = 1

    def __init__(self):
        self._log = core._log
        self._log.debug("Protocol: openhab mqtt contruction")
        self._lock = Event()
        # release lock, ready for next loop
        self._lock.clear()

    def init(self, protocol):
        self._log.debug("Protocol " + name + ": Init")
        self._client_id = protocol['client_id']
        self._server = protocol['hostname']
        self._port = protocol['port']
        self._user = protocol['user']
        self._password = protocol['password']
        self._queue_out1 = {}
        self._queue_out2 = {}
        self._queue_out3 = {}
        self._queue_out = protocol[
            'publish']  #### was commented out AJ, now back in
        self._pubstr = protocol['publish']  #### added AJ
        self._queue_in = protocol['subscribe']
        self._mq = MQTTClient(self._client_id, self._server, self._port,
                              self._user, self._password)
        # Print diagnostic messages when retries/reconnects happens
        self._mq.DEBUG = True
        self._queue = queues.Queue(maxsize=100)
        return self._queue

    def connect(self):
        self._log.debug("Protocol: " + name + ": connect")
        return self._mq.reconnect()

    def disconnect(self):
        self._log.debug("Protocol: " + name + ": disconnect")
        self._mq.disconnect()

    def check(self):
        self._log.debug("Protocol: " + name + ": check")
        self._mq.check_msg()

    def status(self):
        self._log.debug("Protocol: " + name + ": status")
        self._mq.ping()

    def recieve(self):
        self._log.debug("Protocol: " + name + ": recieve")
        self._mq.subscribe(self.queue_in)

    def send(self, devicedata):
        self._log.debug("Protocol: " + name + ": send " + devicedata["stype"])
        # connect or reconnect to mqtt server
        self.connect()
        mqttdata1 = None
        mqttdata2 = None
        mqttdata3 = None

        # case - all sensor types
        while True:
            mqttdata1 = None  # looks like duplication of above!
            mqttdata1 = {}
            mqttdata2 = {}
            mqttdata3 = {}
            self._queue_out1 = ''
            self._queue_out2 = ''
            self._queue_out3 = ''
            message1 = ''
            message2 = ''
            message3 = ''

            # Get next plugin datavalues from utils.py, plugin_senddata(self, queuedata)
            try:
                devicedata['unitname'] = self._queue.get_nowait()
                devicedata['devicename'] = self._queue.get_nowait()
            except Exception as e:
                self._log.debug("Protocol: " + name +
                                " SENSOR_TYPE_SINGLE exception: " + repr(e))
                break

            # case SENSOR_TYPE_SINGLE
            if devicedata["stype"] == core.SENSOR_TYPE_SINGLE:
                # get plugin values
                devicedata['valueV1'] = self._queue.get_nowait()
                devicedata['valueN1'] = self._queue.get_nowait()
                # Assemble mqtt message
                mqttdata1 = {}
                mqttdata1['topic'] = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN1']
                mqttdata1['msg'] = str(devicedata["valueV1"])
                message1 = str(devicedata["valueV1"])
                break

            # case SENSOR_TYPE_LONG
            if devicedata["stype"] == core.SENSOR_TYPE_LONG:
                self._log.debug("Protocol: " + name + ": SENSOR_TYPE_LONG")
                break

            # case SENSOR_TYPE_DUAL
            if devicedata["stype"] == core.SENSOR_TYPE_DUAL:
                self._log.debug("Protocol: " + name + ": SENSOR_TYPE_DUAL")
                break

            # case SENSOR_TYPE_TEMP_HUM
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_HUM:
                self._log.debug("Protocol: " + name + ": SENSOR_TYPE_TEMP_HUM")
                # Get plugin values
                try:
                    devicedata['valueV1'] = self._queue.get_nowait()
                    devicedata['valueN1'] = self._queue.get_nowait()
                    devicedata['valueV2'] = self._queue.get_nowait()
                    devicedata['valueN2'] = self._queue.get_nowait()
                except Exception as e:
                    self._log.debug("Protocol: " + self._name +
                                    " SENSOR_TYPE_TEMP_HUM Exception: " +
                                    repr(e))
                    break

                # Assemble mqtt messages
                mqttdata1 = {}
                mqttdata1['topic'] = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN1']
                mqttdata1['msg'] = str(devicedata["valueV1"])
                message1 = str(devicedata["valueV1"])
                mqttdata2 = {}
                mqttdata2['topic'] = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN2']
                mqttdata2['msg'] = str(devicedata["valueV2"])
                message1 = str(devicedata["valueV2"])
                break

            # case SENSOR_TYPE_TEMP_BARO
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_BARO:
                self._log.debug("Protocol: " + name +
                                ": SENSOR_TYPE_TEMP_BARO")
                break

            # case SENSOR_TYPE_TEMP_HUM_BARO
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_HUM_BARO:
                #self._log.debug("Protocol: "+name+": SENSOR_TYPE_TEMP_HUM_BARO")
                # Get plugin values
                try:
                    devicedata['valueV1'] = self._queue.get_nowait()
                    devicedata['valueN1'] = self._queue.get_nowait()
                    devicedata['valueV2'] = self._queue.get_nowait()
                    devicedata['valueN2'] = self._queue.get_nowait()
                    devicedata['valueV3'] = self._queue.get_nowait()
                    devicedata['valueN3'] = self._queue.get_nowait()
                except Exception as e:
                    self._log.debug("Protocol: " + self._name +
                                    " SENSOR_TYPE_TEMP_HUM_BARO Exception: " +
                                    repr(e))
                    break
                # Assemble mqtt topics for valueV1, V2, V3
                mqttdata1 = {}
                mqttdata1['topic'] = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN1']
                mqttdata1['msg'] = str(devicedata["valueV1"])
                message1 = str(devicedata["valueV1"])
                mqttdata2 = {}
                mqttdata2['topic'] = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN2']
                mqttdata2['msg'] = str(devicedata["valueV2"])
                message2 = str(devicedata["valueV2"])
                mqttdata3 = {}
                mqttdata3['topic'] = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN3']
                mqttdata3['msg'] = str(devicedata["valueV3"])
                message3 = str(devicedata["valueV3"])
                break

            # case SENSOR_TYPE_SWITCH
            if devicedata["stype"] == core.SENSOR_TYPE_SWITCH:
                self._log.debug("Protocol: " + name + ": SENSOR_TYPE_SWITCH")
                # Get plugin values
                try:
                    devicedata['valueV1'] = self._queue.get_nowait()
                    devicedata['valueN1'] = self._queue.get_nowait()
                except Exception as e:
                    self._log.debug("Protocol: " + self._name +
                                    " SENSOR_TYPE_SWITCH Exception: " +
                                    repr(e))
                    break
                # Switches can have many values, OpenHAB (usually) only two: 1 (=on) or 0 (=off)
                switch_on = ['closed', 'press', 'double', 'long', 'on']
                switch_off = ['open', 'release', 'off']

                if devicedata["valueV1"] in switch_on:
                    devicedata["valueV1"] = 1
                elif devicedata["valueV1"] in switch_off:
                    devicedata["valueV1"] = 0
                else:
                    break

                # Assemble mqtt message
                mqttdata1 = {}
                mqttdata1['topic'] = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN1']
                mqttdata1['msg'] = str(devicedata["valueV1"])
                message1 = str(devicedata["valueV1"])
                break

            # case SENSOR_TYPE_DIMMER
            if devicedata["stype"] == core.SENSOR_TYPE_DIMMER:
                self._log.debug("Protocol: " + name + ": SENSOR_TYPE_DIMMER")
                break

            # case SENSOR_TYPE_WIND
            if devicedata["stype"] == core.SENSOR_TYPE_WIND:
                self._log.debug("Protocol: " + name + ": SENSOR_TYPE_WIND")
                break

            # else UNKNOWN
            self._log.debug("Protocol " + name + ": Unknown sensor type!")
            break

        # Now publish the data to the MQTT broker/server

        # test for a user entry in webform protocol 'Publish' field; use it if it exists
        if self._pubstr != '':  # entry exists in Publish field
            self._queue_out1 = self._pubstr
            self._queue_out2 = self._pubstr
            self._queue_out3 = self._pubstr
        else:  # use "standard" format (unitname/devicename/valuename)...
            self._log.debug('Protocol: ' + name + ': "standard" topic format')
            self._queue_out1 = str(mqttdata1['topic'])
            if devicedata.get('valueN2') != None:
                self._queue_out2 = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN2']
            if devicedata.get('valueN3') != None:
                self._queue_out3 = devicedata['unitname'] + "/" + devicedata[
                    'devicename'] + "/" + devicedata['valueN3']

        # Whichever the sensor type, check if we have mqtt data to send, and if so publish it

        # publish datavalue1...
        if message1 != None:
            self._log.debug("Protocol: " + name + " Publish: Topic: " +
                            self._queue_out1 + ", Message: " + message1)
            self._mq.publish(self._queue_out1, message1)

        # publish datavalue2 (if it exists)
        if devicedata.get('valueN2') != None:
            if message2 != None:
                self._log.debug("Protocol: " + name + " Publish: Topic: " +
                                self._queue_out2 + ", Message: " + message2)
                self._mq.publish(self._queue_out2, message2)

        # publish datavalue3 (if it exists)
        if devicedata.get('valueN3') != None:
            if mqttdata3['msg'] != None:
                self._log.debug("Protocol: " + name + " Publish: Topic: " +
                                self._queue_out3 + ", Message: " + message3)
                self._mq.publish(self._queue_out3, message3)

        # we may eventually need more, for example for Dummy device (4 values)...
        # End of send #

    def process(self):
        # processing todo for protocol (main loop of protocol)
        self._log.debug("Protocol: " + name + " Processing...")
        devicedata = {}
        try:
            while True:
                message1 = self._queue.get_nowait(
                )  # keep reading from the protocol queue
                if message1 == core.QUEUE_MESSAGE_START:  # found "start" message
                    break  # ready to read devicedata values
            devicedata['stype'] = self._queue.get_nowait()  # get sensor type
            devicedata['serverid'] = self._queue.get_nowait()  # get server id
            #print("OHmqtt l 266: devicedata = ", devicedata)
            self.send(
                devicedata
            )  # go and get other datavalues as needed, and publish them to MQTT ...
        except Exception as e:
            self._log.debug("Protocol: " + name + " process Exception: " +
                            repr(e))

        # release lock, ready for next processing
        self._lock.clear()
Ejemplo n.º 6
0
class test_plugin:
    gpiotype = "input"  # Default GPIO type
    inputtype = "normal"  # Default GPIO input type
    datastore = None  # Place where plugin data is stored for reboots

    def __init__(self):
        # generic section
        self._log = core._log
        self._log.debug("Plugin: test contruction")
        self._utils = core._utils
        self._plugins = core._plugins
        self._lock = Event()
        # plugin specific section
        self.valuenames = {}
        self.valuenames["valueN1"] = "GPIO"
        self.valuenames["valueF1"] = ""
        self.valuenames["valueD1"] = 0
        # release lock, ready for next measurement
        self._lock.clear()

    def init(self, plugin, device, queue, scriptqueue, rulequeue, valuequeue):
        self._log.debug("Plugin: test init")
        # generic section
        self._utils.plugin_initdata(self, plugin, device, queue, scriptqueue,
                                    rulequeue, valuequeue)
        self.content = plugin.get('content', content)
        self.pincnt = pincnt
        self.valuecnt = valuecnt
        self.stype = stype
        self.dtype = dtype
        self.valuenames['devicename'] = device[
            'name']  # gets device/plugin name, added AJ
        plugin['dtype'] = dtype
        plugin['stype'] = stype
        plugin['template'] = template
        datastore = self._plugins.readstore(name)
        return True

    def loadform(self, plugindata):
        self._log.debug("Plugin: test loadform")
        # generic section
        self._utils.plugin_loadform(self, plugindata)
        # plugin specific section
        plugindata['gpiotype'] = self.gpiotype
        plugindata['inputtype'] = self.inputtype

    def saveform(self, plugindata):
        self._log.debug("Plugin: test saveform")
        # generic section
        self._utils.plugin_saveform(self, plugindata)
        # plugin specific section
        self.gpiotype = plugindata['gpiotype']
        self.inputtype = plugindata['inputtype']
        self.dxpin = plugindata['dxpin0']

    def read(self, values):
        self._log.debug("Plugin: test read")
        # generic section
        values['valueN1'] = self.valuenames["valueN1"]
        # plugin specific section
        values['valueV1'] = 'on'

    def write(self, values):
        self._log.debug("Plugin: test write")

    async def asyncprocess(self):
        self._log.debug("Plugin: test process")
        # send data to protocol and script/rule queues
        self.valuenames["valueV1"] = 'on'
        self._utils.plugin_senddata(self)
        # release lock, ready for next measurement
        self._lock.clear()
Ejemplo n.º 7
0
class NEC_IR():
    def __init__(self, pin, callback, extended,
                 *args):  # Optional args for callback
        self._ev_start = Event()
        self._callback = callback
        self._extended = extended
        self._addr = 0
        self.block_time = 80 if extended else 73  # Allow for some tx tolerance (?)
        self._args = args
        self._times = array('i',
                            (0
                             for _ in range(_EDGECOUNT + 1)))  # +1 for overrun
        if platform == 'pyboard':
            ExtInt(pin, ExtInt.IRQ_RISING_FALLING, Pin.PULL_NONE, self._cb_pin)
        else:  # PR5962 ESP8266 hard IRQ's not supported
            pin.irq(handler=self._cb_pin,
                    trigger=(Pin.IRQ_FALLING | Pin.IRQ_RISING))
        #elif ESP32:
        #pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING))
        #else:
        #pin.irq(handler = self._cb_pin, trigger = (Pin.IRQ_FALLING | Pin.IRQ_RISING), hard = True)
        self._edge = 0
        self._ev_start.clear()
        loop = asyncio.get_event_loop()
        loop.create_task(self._run())

    async def _run(self):
        loop = asyncio.get_event_loop()
        while True:
            await self._ev_start  # Wait until data collection has started
            # Compensate for asyncio latency
            latency = ticks_diff(loop.time(), self._ev_start.value())
            await asyncio.sleep_ms(self.block_time - latency
                                   )  # Data block should have ended
            self._decode()  # decode, clear event, prepare for new rx, call cb

    # Pin interrupt. Save time of each edge for later decode.
    def _cb_pin(self, line):
        t = ticks_us()
        # On overrun ignore pulses until software timer times out
        if self._edge <= _EDGECOUNT:  # Allow 1 extra pulse to record overrun
            if not self._ev_start.is_set():  # First edge received
                loop = asyncio.get_event_loop()
                self._ev_start.set(loop.time())  # asyncio latency compensation
            self._times[self._edge] = t
            self._edge += 1

    def _decode(self):
        overrun = self._edge > _EDGECOUNT
        val = OVERRUN if overrun else BADSTART
        if not overrun:
            width = ticks_diff(self._times[1], self._times[0])
            if width > 4000:  # 9ms leading mark for all valid data
                width = ticks_diff(self._times[2], self._times[1])
                if width > 3000:  # 4.5ms space for normal data
                    if self._edge < _EDGECOUNT:
                        # Haven't received the correct number of edges
                        val = BADBLOCK
                    else:
                        # Time spaces only (marks are always 562.5µs)
                        # Space is 1.6875ms (1) or 562.5µs (0)
                        # Skip last bit which is always 1
                        val = 0
                        for edge in range(3, _EDGECOUNT - 2, 2):
                            val >>= 1
                            if ticks_diff(self._times[edge + 1],
                                          self._times[edge]) > 1120:
                                val |= 0x80000000
                elif width > 1700:  # 2.5ms space for a repeat code. Should have exactly 4 edges.
                    val = REPEAT if self._edge == 4 else BADREP
        addr = 0
        if val >= 0:  # validate. Byte layout of val ~cmd cmd ~addr addr
            addr = val & 0xff
            cmd = (val >> 16) & 0xff
            if addr == ((val >> 8) ^ 0xff) & 0xff:  # 8 bit address OK
                val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA
                self._addr = addr
            else:
                addr |= val & 0xff00  # pass assumed 16 bit address to callback
                if self._extended:
                    val = cmd if cmd == (val >> 24) ^ 0xff else BADDATA
                    self._addr = addr
                else:
                    val = BADADDR
        if val == REPEAT:
            addr = self._addr  # Last valid addresss
        self._edge = 0  # Set up for new data burst and run user callback
        self._ev_start.clear()
        self._callback(val, addr, *self._args)
Ejemplo n.º 8
0
class domoticz_http_protocol:
    processcnt = 1

    def __init__(self):
        self._log = core._log
        self._log.debug("Protocol: domoticz http contruction")
        self._lock = Event()
        # release lock, ready for next loop
        self._lock.clear()

    def init(self, protocol):
        self._log.debug("Protocol " + name + ": Init")
        self._client_id = protocol['client_id']
        self._server = protocol['hostname']
        self._port = protocol['port']
        self._user = protocol['user']
        self._password = protocol['password']
        self._queue = queues.Queue(maxsize=100)
        return self._queue

    def connect(self):
        self._log.debug("Protocol " + name + ": connect")

    def disconnect(self):
        self._log.debug("Protocol " + name + ": disconnect")

    def check(self):
        self._log.debug("Protocol " + name + ": check")

    def status(self):
        self._log.debug("Protocol " + name + ": status")

    def receive(self):
        self._log.debug("Protocol " + name + ": recieve")

    def send(self, devicedata):
        self._log.debug("Protocol " + name + ": send " + devicedata["stype"])
        # Assemble server url
        message = None
        # case
        while True:

            # case SENSOR_TYPE_SINGLE
            if devicedata["stype"] == core.SENSOR_TYPE_SINGLE:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_SINGLE")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                except Exception:
                    self._log.debug(
                        "Protocol " + name +
                        " SENSOR_TYPE_TEMP_HUM exception: Queue Emtpy!")
                    break

                # Assemble http message
                message = "/json.htm?type=command&param=udevice&idx=" + str(
                    devicedata["serverid"]) + "&nvalue=0&svalue=" + str(
                        devicedata["value1"]) + ";0"
                break

            # case SENSOR_TYPE_LONG
            if devicedata["stype"] == core.SENSOR_TYPE_LONG:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_LONG")
                break

            # case SENSOR_TYPE_DUAL
            if devicedata["stype"] == core.SENSOR_TYPE_DUAL:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_DUAL")
                break

            # case SENSOR_TYPE_TEMP_HUM
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_HUM:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_TEMP_HUM")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                    devicedata['value2'] = self._queue.get_nowait()
                except Exception:
                    self._log.debug(
                        "Protocol " + name +
                        " SENSOR_TYPE_TEMP_HUM exception: Queue Emtpy!")
                    break
                # Assemble http message
                message = "/json.htm?type=command&param=udevice&idx=" + str(
                    devicedata["serverid"]) + "&nvalue=0&svalue=" + str(
                        devicedata["value1"]) + str(
                            devicedata["value2"]) + ";0"
                break

            # case SENSOR_TYPE_TEMP_BARO
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_BARO:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_TEMP_BARO")
                break

            # case SENSOR_TYPE_TEMP_HUM_BARO
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_HUM_BARO:
                self._log.debug("Protocol " + name +
                                ": SENSOR_TYPE_TEMP_HUM_BARO")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                    devicedata['value2'] = self._queue.get_nowait()
                    devicedata['value3'] = self._queue.get_nowait()
                except Exception:
                    self._log.debug(
                        "Protocol " + name +
                        " SENSOR_TYPE_TEMP_HUM_BARO exception: Queue Emtpy!")
                    break
                # Assemble http message
                message = "/json.htm?type=command&param=udevice&idx=" + str(
                    devicedata["serverid"]) + "&nvalue=0&svalue=" + str(
                        devicedata["value1"]) + str(
                            devicedata["value2"]) + ";0;" + str(
                                devicedata["value3"]) + ";0"
                break

            # case SENSOR_TYPE_SWITCH
            if devicedata["stype"] == core.SENSOR_TYPE_SWITCH:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_SWITCH")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                except Exception:
                    self._log.debug(
                        "Protocol " + name +
                        " SENSOR_TYPE_SWITCH exception: Queue Emtpy!")
                    break

                # Switches can have many values, domoticz only two: on or off
                switch_on = ['closed', 'press', 'double', 'long']
                switch_off = ['open', 'release']

                if devicedata["value1"] in switch_on:
                    devicedata["value1"] = 'On'
                elif devicedata["value1"] in switch_off:
                    devicedata["value1"] = 'Off'
                else:
                    break

                # Assemble http message
                message = "/json.htm?type=command&param=switchlight&idx=" + str(
                    devicedata["serverid"]
                ) + "&switchcmd=" + devicedata["value1"]
                break

            # case SENSOR_TYPE_DIMMER
            if devicedata["stype"] == core.SENSOR_TYPE_DIMMER:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_DIMMER")
                break

            # case SENSOR_TYPE_WIND
            if devicedata["stype"] == core.SENSOR_TYPE_WIND:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_WIND")
                break

            # else UNKNOWN
            self._log.debug("Protocol " + name + ": Unknown sensor type!")
            break

        if message != None:
            self._log.debug("Protocol " + name + " message: " + "http://" +
                            self._server + ":" + str(self._port) + message)
            # Send data
            try:
                response = urequests.get("http://" + self._server + ":" +
                                         str(self._port) + message)
                self._log.debug("Protocol " + name + " response: " +
                                response.text)
                response.close()
            except OSError as e:
                self._log.debug("Protocol " + name + " Exception: " + repr(e))
            #self._log.debug("Protocol "+name+" response: "+resp.read().decode("utf-8"))

    def process(self):
        # processing todo for protocol
        self._log.debug("Protocol " + name)
        devicedata = {}
        try:
            while self._queue.get_nowait() != core.QUEUE_MESSAGE_START:
                pass
            devicedata['stype'] = self._queue.get_nowait()
            devicedata['serverid'] = self._queue.get_nowait()
        except Exception as e:
            self._log.debug("Protocol " + name + " proces Exception: " +
                            repr(e))
        self.send(devicedata)

        # release lock, ready for next processing
        self._lock.clear()
Ejemplo n.º 9
0
class ssd1306_plugin:
    datastore           = None                      # Place where plugin data is stored for reboots
    
    def __init__(self) :
        # generic section
        self._log       = core._log
        self._log.debug("Plugin: ssd1306 contruction")
        self._utils     = core._utils
        self._plugins   = core._plugins
        self._lock      = Event()
        # plugin specific section
        self.valuenames = {}
        self.valuenames["valueN1"]= ""
        self.valuenames["valueF1"]= ""
        self.valuenames["valueD1"]= 0
        # release lock, ready for next measurement
        self._lock.clear()
        
    def init(self, plugin, device, queue, scriptqueue):        
        self._log.debug("Plugin: ssd1306 init")
        # generic section
        self._utils.plugin_initdata(self, plugin, device, queue, scriptqueue)
        self.content            = plugin.get('content',content)
        self.pincnt             = pincnt
        self.valuecnt           = valuecnt
        self.stype              = stype
        self.dtype              = dtype
        self.ssd_i2c            = ssd_i2c
        self.ssd_rotation       = ssd_rotation
        self.ssd_width          = ssd_width
        self.ssd_height         = ssd_height
        self.ssd_timeout        = ssd_timeout
        self.ssd_line1          = ssd_line1
        self.ssd_line2          = ssd_line2
        self.ssd_line3          = ssd_line3
        self.ssd_line4          = ssd_line4
        self.ssd_line5          = ssd_line5
        self.ssd_line6          = ssd_line6
        self.ssd_line7          = ssd_line7
        self.ssd_line8          = ssd_line8
        self._device            = device
        plugin['dtype']         = dtype
        plugin['stype']         = stype
        plugin['template']      = template
        datastore               = self._plugins.readstore(name)
        # Load values
        self._plugins.loadvalues(self._device,self.valuenames)
        
        # Set triggers
        self.triggers           = name+"#"+self.valuenames["valueN1"]
        self._plugins.triggers(device, self.triggers)
        return True

    def loadform(self,plugindata):
        self._log.debug("Plugin: ssd1306 loadform")
        # generic section
        self._utils.plugin_loadform(self, plugindata)
        # plugin specific section
        plugindata["ssd_i2c"]      = self.ssd_i2c
        plugindata["ssd_rotation"] = self.ssd_rotation
        plugindata["ssd_height"]   = self.ssd_height
        plugindata["ssd_width"]    = self.ssd_width 
        plugindata["ssd_timeout"]  = self.ssd_timeout
        
    def saveform(self,plugindata):
        self._log.debug("Plugin: ssd1306 saveform")
        # generic section
        self._utils.plugin_saveform(self, plugindata)
        # plugin specific section
        self._plugins.savevalues(self._device,self.valuenames)
        
    def read(self, values):
        self._log.debug("Plugin: ssd1306 read")
        # generic section
        values['valueN1'] = self.valuenames["valueN1"]
        # plugin specific section
        values['valueV1'] = 'on'

    def write(self, values):
        self._log.debug("Plugin: ssd1306 write")
        #print(values)
        
    async def asyncprocess(self):
        self._log.debug("Plugin: ssd1306 process")
        # send data to protocol and script/rule queues
        self.valuenames["valueV1"] = 'on'        
        self._utils.plugin_senddata(self)
        # release lock, ready for next measurement
        self._lock.clear()
Ejemplo n.º 10
0
class switch_plugin:
    inputtype = "normal"  # Default switch type
    datastore = None  # Place where plugin data is stored for reboots

    def __init__(self):
        # generic section
        self._log = core._log
        self._log.debug("Plugin: switch contruction")
        self._utils = core._utils
        self._plugins = core._plugins
        self._hal = core._hal
        self._lock = Event()
        self.dxpin = dxpin
        # plugin specific section
        self.valuenames = {}
        self.valuenames["valueN1"] = "switch"
        self.valuenames["valueF1"] = ""
        self.valuenames["valueD1"] = 0
        # release lock, ready for next measurement
        self._lock.clear()

    def init(self, plugin, device, queue, scriptqueue):
        self._log.debug("Plugin: switch init")
        # generic section
        self._utils.plugin_initdata(self, plugin, device, queue, scriptqueue)
        self.content = plugin.get('content', content)
        plugin['dtype'] = dtype
        plugin['stype'] = stype
        plugin['template'] = template
        datastore = self._plugins.readstore(self.devicename)
        # plugin specific section
        self.switch_status = bootstate
        if self.inputtype == 'normal':
            self._log.debug("Plugin: switch init normal, pin: " + self.dxpin)
            # Setup switch
            self.swpin = self._hal.pin(self.dxpin, core.PIN_IN,
                                       core.PIN_PULL_UP)
            self.switch = Switch(self.swpin)
            # Register coros to launch on contact close and open
            self.switch.close_func(self.asyncswitchopen)
            self.switch.open_func(self.asyncswitchclosed)
        elif self.inputtype == 'low':
            self._log.debug("Plugin: switch init low, pin: " + self.dxpin)
            # Setup button active low
            self.swpin = self._hal.pin(self.dxpin, core.PIN_IN,
                                       core.PIN_PULL_UP)
            self.switch = Pushbutton(self.swpin)
            self.switch.press_func(self.asyncbuttonpress)
            self.switch.release_func(self.asyncbuttonrelease)
            self.switch.double_func(self.asyncbuttondouble)
            self.switch.long_func(self.asyncbuttonlong)
        else:
            self._log.debug("Plugin: switch init high, pin: " + self.dxpin)
            # Setup button active high
            self.swpin = self._hal.pin(self.dxpin, core.PIN_IN,
                                       core.PIN_PULL_DOWN)
            self.switch = Pushbutton(self.swpin)
            self.switch.press_func(self.asyncbuttonpress)
            self.switch.release_func(self.asyncbuttonrelease)
            self.switch.double_func(self.asyncbuttondouble)
            self.switch.long_func(self.asyncbuttonlong)
        return True

    def loadform(self, plugindata):
        self._log.debug("Plugin: switch loadform")
        # generic section
        self._utils.plugin_loadform(self, plugindata)
        # plugin specific section
        plugindata['inputtype'] = self.inputtype
        plugindata['dxpin0'] = self.dxpin

    def saveform(self, plugindata):
        self._log.debug("Plugin: switch saveform")
        # generic section
        self._utils.plugin_saveform(self, plugindata)
        # plugin specific section
        self.inputtype = plugindata['inputtype']
        self.dxpin = plugindata['dxpin0']

        # store values
        data = {}
        data["inputtype"] = self.inputtype
        data["dxpin"] = self.dxpin
        data["valueN1"] = self.valuenames["valueN1"]
        data["valueF1"] = self.valuenames["valueF1"]
        data["valueD1"] = self.valuenames["valueD1"]
        self._plugins.writestore(self.devicename, data)

        if self.inputtype == 'normal':
            # Setup switch
            self.swpin = self._hal.pin(self.dxpin, core.PIN_IN,
                                       core.PIN_PULL_UP)
            self.switch = Switch(self.swpin)
            # Register coros to launch on contact close and open
            self.switch.close_func(self.asyncswitchopen)
            self.switch.open_func(self.asyncswitchclosed)
        elif self.inputtype == 'low':
            # Setup button active low
            self.swpin = self._hal.pin(self.dxpin, core.PIN_IN,
                                       core.PIN_PULL_UP)
            self.switch = Pushbutton(self.swpin)
            self.switch.press_func(self.asyncbuttonpress)
            self.switch.release_func(self.asyncbuttonrelease)
            self.switch.double_func(self.asyncbuttondouble)
            self.switch.long_func(self.asyncbuttonlong)
        else:
            # Setup button active high
            self.swpin = self._hal.pin(self.dxpin, core.PIN_IN,
                                       core.PIN_PULL_DOWN)
            self.switch.press_func(self.asyncbuttonpress)
            self.switch.release_func(self.asyncbuttonrelease)
            self.switch.double_func(self.asyncbuttondouble)
            self.switch.long_func(self.asyncbuttonlong)

    def read(self, values):
        self._log.debug("Plugin: switch read")
        # generic section
        values['valueN1'] = self.valuenames["valueN1"]
        values['valueD1'] = self.switch_status

    def write(self, values):
        self._log.debug("Plugin: switch write")

    async def asyncprocess(self):
        self._log.debug("Plugin: switch process")
        # plugin specific section
        # If a switch occured
        if self.switch_status:
            # send data to protocol and script/rule queues
            self.valuenames["valueD1"] = self.switch_status
            self._utils.plugin_senddata(self)
            # erase status
            self.switch_status = ""
        # release lock, ready for next measurement
        self._lock.clear()

    #
    #CUSTOM SENSOR CODE...
    #

    async def asyncswitchopen(self):
        self.switch_status = 'open'
        # release lock, ready for next measurement
        self._lock.clear()

    async def asyncswitchclosed(self):
        self.switch_status = 'closed'
        # release lock, ready for next measurement
        self._lock.clear()

    async def asyncbuttonpress(self):
        self.switch_status = 'press'
        # release lock, ready for next measurement
        self._lock.clear()

    async def asyncbuttonrelease(self):
        self.switch_status = 'release'
        # release lock, ready for next measurement
        self._lock.clear()

    async def asyncbuttondouble(self):
        self.switch_status = 'double'
        # release lock, ready for next measurement
        self._lock.clear()

    async def asyncbuttonlong(self):
        self.switch_status = 'long'
        # release lock, ready for next measurement
        self._lock.clear()
Ejemplo n.º 11
0
class bme280_plugin:
    valuenames          = {}
    datastore           = None
    
    def __init__(self) :
        # generic section
        self._log       = core._log
        self._log.debug("Plugin: bme280 contruction")
        self._utils     = core._utils
        self._plugins   = core._plugins
        self._lock      = Event()
        # plugin specific section
        self.valuenames["valueV1"] = 0 # added by AJ
        self.valuenames["valueV2"] = 0 # added by AJ
        self.valuenames["valueV3"] = 0 # added by AJ
        self.valuenames["valueN1"]= "Temperature"
        self.valuenames["valueN2"]= "Humidity"
        self.valuenames["valueN3"]= "Pressure"
        self.valuenames["valueF1"]= ""
        self.valuenames["valueF2"]= ""
        self.valuenames["valueF3"]= ""
        self.valuenames["valueD1"]= 0
        self.valuenames["valueD2"]= 0
        self.valuenames["valueD3"]= 0
        # release lock, ready for next measurement
        self._lock.clear()
        
    def init(self, plugin, device, queue, scriptqueue):        
        self._log.debug("Plugin: bme280 init")
        # plugin generic section
        self._utils.plugin_initdata(self, plugin, device, queue, scriptqueue)
        self.content            = plugin.get('content',content)
        self.pincnt             = pincnt
        self.valuecnt           = valuecnt
        self.stype              = stype
        self.valuenames['devicename'] = device['name'] # gets device/plugin name, added AJ
        plugin['dtype']         = dtype
        plugin['stype']         = stype
        plugin['template']      = template
        datastore               = self._plugins.readstore(device["name"])
        # plugin specific section
        self.bme_elev           = bme_elev
        self.i2c_addr            = i2c_addr
        self.i2c                = core._hal.get_i2c(i2c)
        if self.i2c != None: 
            try:
                self._log.debug("Plugin: bme280 init i2c")
                self.bme280_init(address=self.i2c_addr)
            except OSError as e:
                self._log.debug("Plugin: bme280 init OSError exception: "+repr(e))
                return False
        return True

    def loadform(self,plugindata):
        self._log.debug("Plugin: bme280 loadform")
        # generic section
        self._utils.plugin_loadform(self, plugindata)
        plugindata['i2c']   = i2c
        plugindata['i2c_addr']   = self.i2c_addr
        # plugin specific section
        plugindata['bme_elev']  = self.bme_elev
        
    def saveform(self,plugindata):
        self._log.debug("Plugin: bme280 saveform")
        # generic section
        self._utils.plugin_saveform(self, plugindata)
        sf_i2c                  = plugindata.get('i2c',None)
        if sf_i2c: self.sf_i2c = int(sf_i2c)
        else: self.sf_i2c = None
        sf_i2c_addr                  = plugindata.get('i2c_addr',None)
        if sf_i2c_addr: self.i2c_addr = int(sf_i2c_addr)
        else: self.i2c_addr = None
        # plugin specific section
        sf_bme_elev                 = plugindata.get('bme_elev',None)
        if sf_bme_elev: self.bme_elev = int(sf_bme_elev)
        else: self.bme_elev = None
        self.i2c                    = core._hal.get_i2c(i2c)
        if self.i2c:
            try:
                if self.i2c != None: self.bme280_init(address=self.i2c_addr)
            except OSError as e:
                self._log.debug("Plugin: bme280 saveform OSError exception: "+repr(e))

    def read(self, values):
        self._log.debug("Plugin: bme280 read")
        # generic section
        values['valueN1'] = self.valuenames["valueN1"]
        values['valueN2'] = self.valuenames["valueN2"]
        values['valueN3'] = self.valuenames["valueN3"]
        
        #values['valueV1'] = round(self.valuenames["valueV1"], int(self.valuenames['valueD1']) ) # temp, specify decimal places
        #values['valueV2'] = round(self.valuenames["valueV2"], int(self.valuenames['valueD2']) ) # hum, specify decimal places
        #values['valueV3'] = round(self.valuenames["valueV3"], int(self.valuenames['valueD3']) ) # press, specify decimal places
        
        
        # plugin specific section
        if self.i2c != None: 
            try:
                dvalues = self.bme280_values()
                #print("bme280.py l.153: dvalues =", dvalues)
            except Exception as e:
                self._log.debug("Plugin: bme280 read exception: "+repr(e))
                values['valueV1'] = ''
                values['valueV2'] = ''
                values['valueV3'] = ''
                return values
            values["valueV1"] = round(float(dvalues[0]), int(self.valuenames['valueD1']) ) # temp, specify decimal places
            values["valueV2"] = round(float(dvalues[2]), int(self.valuenames['valueD2']) ) # hum, specify decimal places
            values["valueV3"] = round(float(dvalues[1]), int(self.valuenames['valueD3']) ) # press, specify decimal places
        else:
            self._log.debug("Plugin: BME280 read, empty values")
            # empty values
            values['valueV1'] = ''
            values['valueV2'] = ''
            values['valueV3'] = ''
        return values
   
    def write(self):
        self._log.debug("Plugin: bme280 write")

    async def asyncprocess(self):
        # plugin specific section
        self._log.debug("Plugin: bme280 process")
        if self.i2c: 
            try:
                t, p, h = self.bme280_read_compensated_data()
            except Exception as e:
                self._log.debug("Plugin: bme280 process exception: "+repr(e))
                # release lock, ready for next measurement
                self._lock.clear()
                return
            # send data to protocol and script/rule queues
            self.valuenames["valueV1"] = round(t/100, int(self.valuenames['valueD1']) ) # temp, specify decimal places
            self.valuenames["valueV2"] = round(h/1024, int(self.valuenames['valueD2']) ) # hum, specify decimal places
            self.valuenames["valueV3"] = round(p/25600, int(self.valuenames['valueD3']) ) # press, specify decimal places
            self._utils.plugin_senddata(self)
        # release lock, ready for next measurement
        self._lock.clear()
        
    #
    #CUSTOM SENSOR CODE...    
    #
    
    def bme280_init(self,
                 mode=BME280_OSAMPLE_1,
                 address=BME280_I2CADDR,
                 **kwargs):
        # Check that mode is valid.
        if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
                        BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
            raise ValueError(
                'Unexpected mode value {0}. Set mode to one of '
                'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
                'BME280_ULTRAHIGHRES'.format(mode))
        self._mode = mode
        self.address = address

        # load calibration data
        dig_88_a1 = self.i2c.readfrom_mem(self.address, 0x88, 26)
        dig_e1_e7 = self.i2c.readfrom_mem(self.address, 0xE1, 7)
        self.dig_T1, self.dig_T2, self.dig_T3, self.dig_P1, \
            self.dig_P2, self.dig_P3, self.dig_P4, self.dig_P5, \
            self.dig_P6, self.dig_P7, self.dig_P8, self.dig_P9, \
            _, self.dig_H1 = unpack("<HhhHhhhhhhhhBB", dig_88_a1)

        self.dig_H2, self.dig_H3 = unpack("<hB", dig_e1_e7)
        e4_sign = unpack_from("<b", dig_e1_e7, 3)[0]
        self.dig_H4 = (e4_sign << 4) | (dig_e1_e7[4] & 0xF)

        e6_sign = unpack_from("<b", dig_e1_e7, 5)[0]
        self.dig_H5 = (e6_sign << 4) | (dig_e1_e7[4] >> 4)

        self.dig_H6 = unpack_from("<b", dig_e1_e7, 6)[0]

        self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
                             bytearray([0x3F]))
        self.t_fine = 0

        # temporary data holders which stay allocated
        self._l1_barray = bytearray(1)
        self._l8_barray = bytearray(8)
        self._l3_resultarray = array("i", [0, 0, 0])

    def bme280_read_raw_data(self, result):
        """ Reads the raw (uncompensated) data from the sensor.

            Args:
                result: array of length 3 or alike where the result will be
                stored, in temperature, pressure, humidity order
            Returns:
                None
        """

        self._l1_barray[0] = self._mode
        self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL_HUM,
                             self._l1_barray)
        self._l1_barray[0] = self._mode << 5 | self._mode << 2 | 1
        self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
                             self._l1_barray)

        sleep_time = 1250 + 2300 * (1 << self._mode)
        sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
        sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
        time.sleep_us(sleep_time)  # Wait the required time

        # burst readout from 0xF7 to 0xFE, recommended by datasheet
        self.i2c.readfrom_mem_into(self.address, 0xF7, self._l8_barray)
        readout = self._l8_barray
        # pressure(0xF7): ((msb << 16) | (lsb << 8) | xlsb) >> 4
        raw_press = ((readout[0] << 16) | (readout[1] << 8) | readout[2]) >> 4
        # temperature(0xFA): ((msb << 16) | (lsb << 8) | xlsb) >> 4
        raw_temp = ((readout[3] << 16) | (readout[4] << 8) | readout[5]) >> 4
        # humidity(0xFD): (msb << 8) | lsb
        raw_hum = (readout[6] << 8) | readout[7]

        result[0] = raw_temp
        result[1] = raw_press
        result[2] = raw_hum

    def bme280_read_compensated_data(self, result=None):
        """ Reads the data from the sensor and returns the compensated data.

            Args:
                result: array of length 3 or alike where the result will be
                stored, in temperature, pressure, humidity order. You may use
                this to read out the sensor without allocating heap memory

            Returns:
                array with temperature, pressure, humidity. Will be the one from
                the result parameter if not None
        """
        self.bme280_read_raw_data(self._l3_resultarray)
        raw_temp, raw_press, raw_hum = self._l3_resultarray
        # temperature
        var1 = ((raw_temp >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
        var2 = (((((raw_temp >> 4) - self.dig_T1) *
                  ((raw_temp >> 4) - self.dig_T1)) >> 12) * self.dig_T3) >> 14
        self.t_fine = var1 + var2
        temp = (self.t_fine * 5 + 128) >> 8

        # pressure
        var1 = self.t_fine - 128000
        var2 = var1 * var1 * self.dig_P6
        var2 = var2 + ((var1 * self.dig_P5) << 17)
        var2 = var2 + (self.dig_P4 << 35)
        var1 = (((var1 * var1 * self.dig_P3) >> 8) +
                ((var1 * self.dig_P2) << 12))
        var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
        if var1 == 0:
            pressure = 0
        else:
            p = 1048576 - raw_press
            p = (((p << 31) - var2) * 3125) // var1
            var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
            var2 = (self.dig_P8 * p) >> 19
            pressure = ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)

        # humidity
        h = self.t_fine - 76800
        h = (((((raw_hum << 14) - (self.dig_H4 << 20) -
                (self.dig_H5 * h)) + 16384)
              >> 15) * (((((((h * self.dig_H6) >> 10) *
                            (((h * self.dig_H3) >> 11) + 32768)) >> 10) +
                          2097152) * self.dig_H2 + 8192) >> 14))
        h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
        h = 0 if h < 0 else h
        h = 419430400 if h > 419430400 else h
        humidity = h >> 12

        if result:
            result[0] = temp
            result[1] = pressure
            result[2] = humidity
            return result

        return array("i", (temp, pressure, humidity))

    def bme280_values(self):
        """ human readable values """

        t, p, h = self.bme280_read_compensated_data()

        p = p // 256
        pi = p // 100
        pd = p - pi * 100

        hi = h // 1024
        hd = h * 100 // 1024 - hi * 100
        return ("{}".format(t / 100), "{}.{:02d}".format(pi, pd), # edited AJ, remove non-numerics
                "{}.{:02d}".format(hi, hd))
Ejemplo n.º 12
0
class Copernicus_GPS(gps.GPS):
    _enable_sentences = {
        'GGA': (1 << 0),
        'GLL': (1 << 1),
        'VTG': (1 << 2),
        'GSV': (1 << 3),
        'GSA': (1 << 4),
        'ZDA': (1 << 5),
        'RMC': (1 << 8),
        'TF': (1 << 9),
        'BA': (1 << 13)
    }

    class PPS_Mode:
        OFF = 0
        ON = 1
        FIX = 2

    class PPS_Polarity:
        ACTIVE_LOW = 0
        ACTIVE_HIGH = 1

    # we have some special events for config apply
    def __init__(self, uart):
        super().__init__(uart)
        self._nm_ack = Event()
        self._ps_ack = Event()

    # Additional incoming message processing (on to of gps.py)

    # PTNLRNM - Automatic Message Output (Response)
    async def _rx_ptnlrnm(self, segs):
        self._nm_ack.set()
        return

    # PTNLRPS - PPS Configuration (Response)
    async def _rx_ptnlrps(self, segs):
        self._ps_ack.set()
        return

    async def set_auto_messages(self, types, interval):
        # compute bitmask to enable messages
        bitmask = 0
        for type in types:
            bitmask |= self._enable_sentences[type]
        #print(bin(bitmask))
        # send the command
        fmt = 'PTNLSNM,{:04x},{:02d}'
        #print(fmt.format(bitmask,interval))
        print('gps: setting auto messages to', types, 'every', interval,
              'seconds')
        await self._send(fmt.format(bitmask, interval))
        # wait for ack
        print('gps: awaiting messages config ack')
        await self._nm_ack
        self._nm_ack.clear()
        print('gps: messages config accepted')
        return

    async def set_pps_mode(self, mode, length_ns, polarity, cable_ns):
        fmt = 'PTNLSPS,{},{},{},{}'
        # length is in 1/100th of ns
        length_ns = int(length_ns / 100)
        print('gps: setting PPS config')
        await self._send(fmt.format(mode, length_ns, polarity, cable_ns))
        print('gps: awaiting ack to PPS config')
        await self._ps_ack
        self._ps_ack.clear()
        print('gps: PPS config accepted')
        return
Ejemplo n.º 13
0
class domoticz_mqtt_protocol:
    processcnt = 1

    def __init__(self):
        self._log = core._log
        self._log.debug("Protocol: domoticz mqtt contruction")
        self._lock = Event()
        # release lock, ready for next loop
        self._lock.clear()

    def init(self, protocol):
        self._log.debug("Protocol " + name + ": Init")
        self._client_id = protocol['client_id']
        self._server = protocol['hostname']
        self._port = protocol['port']
        self._user = protocol['user']
        self._password = protocol['password']
        self._queue_out = protocol['publish']
        self._queue_in = protocol['subscribe']
        self._mq = MQTTClient(self._client_id, self._server, self._port,
                              self._user, self._password)
        # Print diagnostic messages when retries/reconnects happens
        #self._mq.DEBUG = True
        self._queue = queues.Queue(maxsize=100)
        return self._queue

    def connect(self):
        self._log.debug("Protocol " + name + ": connect")
        return self._mq.reconnect()

    def disconnect(self):
        self._log.debug("Protocol " + name + ": disconnect")
        self._mq.disconnect()

    def check(self):
        self._log.debug("Protocol " + name + ": check")
        self._mq.check_msg()

    def status(self):
        self._log.debug("Protocol " + name + ": status")
        self._mq.ping()

    def recieve(self):
        self._log.debug("Protocol " + name + ": recieve")
        self._mq.subscribe(self.queue_in)

    def send(self, devicedata):
        self._log.debug("Protocol " + name + ": send " + devicedata["stype"])
        # connect or reconnect to mqtt server
        self.connect()
        mqttdata = None
        # case
        while True:
            mqttdata = None

            # case SENSOR_TYPE_SINGLE
            if devicedata["stype"] == core.SENSOR_TYPE_SINGLE:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_SINGLE")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                except Exception as e:
                    self._log.debug("Protocol " + name +
                                    " SENSOR_TYPE_SINGLE exception: " +
                                    repr(e))
                    break

                # Assemble mqtt message
                mqttdata = {}
                mqttdata["idx"] = devicedata["serverid"]
                mqttdata["nvalue"] = 0
                mqttdata["svalue"] = str(devicedata["value1"])
                message = ujson.dumps(mqttdata)
                break

            # case SENSOR_TYPE_LONG
            if devicedata["stype"] == core.SENSOR_TYPE_LONG:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_LONG")
                break

            # case SENSOR_TYPE_DUAL
            if devicedata["stype"] == core.SENSOR_TYPE_DUAL:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_DUAL")
                break

            # case SENSOR_TYPE_TEMP_HUM
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_HUM:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_TEMP_HUM")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                    devicedata['value2'] = self._queue.get_nowait()
                except Exception as e:
                    self._log.debug("Protocol " + self._name +
                                    " SENSOR_TYPE_TEMP_HUM Exception: " +
                                    repr(e))
                    break
                # Assemble mqtt message
                mqttdata = {}
                mqttdata["idx"] = devicedata["serverid"]
                mqttdata["nvalue"] = 0
                mqttdata["svalue"] = str(devicedata["value1"]) + ";" + str(
                    devicedata["value2"]) + ";0"
                message = ujson.dumps(mqttdata)
                break

            # case SENSOR_TYPE_TEMP_BARO
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_BARO:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_TEMP_BARO")
                break

            # case SENSOR_TYPE_TEMP_HUM_BARO
            if devicedata["stype"] == core.SENSOR_TYPE_TEMP_HUM_BARO:
                self._log.debug("Protocol " + name +
                                ": SENSOR_TYPE_TEMP_HUM_BARO")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                    devicedata['value2'] = self._queue.get_nowait()
                    devicedata['value3'] = self._queue.get_nowait()
                except Exception as e:
                    self._log.debug("Protocol " + self._name +
                                    " SENSOR_TYPE_TEMP_HUM_BARO Exception: " +
                                    repr(e))
                    break
                # Assemble mqtt message
                mqttdata = {}
                mqttdata["idx"] = devicedata["serverid"]
                mqttdata["nvalue"] = 0
                mqttdata["svalue"] = str(devicedata["value1"]) + ";" + str(
                    devicedata["value2"]) + ";0;" + str(
                        devicedata["value3"]) + ";0"
                message = ujson.dumps(mqttdata)
                break

            # case SENSOR_TYPE_SWITCH
            if devicedata["stype"] == core.SENSOR_TYPE_SWITCH:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_SWITCH")
                # Get plugin values
                try:
                    devicedata['value1'] = self._queue.get_nowait()
                except Exception as e:
                    self._log.debug("Protocol " + self._name +
                                    " SENSOR_TYPE_SWITCH Exception: " +
                                    repr(e))
                    break

                # Switches can have many values, domoticz only two: on or off
                switch_on = ['closed', 'press', 'double', 'long']
                switch_off = ['open', 'release']

                if devicedata["value1"] in switch_on:
                    devicedata["value1"] = 'On'
                elif devicedata["value1"] in switch_off:
                    devicedata["value1"] = 'Off'
                else:
                    break

                # Assemble mqtt message
                mqttdata = {}
                mqttdata["command"] = "switchlight"
                mqttdata["idx"] = devicedata["serverid"]
                mqttdata["switchcmd"] = devicedata["value1"]
                message = ujson.dumps(mqttdata)
                break

            # case SENSOR_TYPE_DIMMER
            if devicedata["stype"] == core.SENSOR_TYPE_DIMMER:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_DIMMER")
                break

            # case SENSOR_TYPE_WIND
            if devicedata["stype"] == core.SENSOR_TYPE_WIND:
                self._log.debug("Protocol " + name + ": SENSOR_TYPE_WIND")
                break

            # else UNKNOWN
            self._log.debug("Protocol " + name + ": Unknown sensor type!")
            break

        if mqttdata != None:
            self._log.debug("Protocol " + name + ": Message: " + message)
            self._mq.publish(self._queue_out, message)

    def process(self):
        # processing todo for protocol
        self._log.debug("Protocol " + name + " Processing...")
        devicedata = {}
        try:
            while True:
                message = self._queue.get_nowait()
                if message == core.QUEUE_MESSAGE_START:
                    break
            devicedata['stype'] = self._queue.get_nowait()
            devicedata['serverid'] = self._queue.get_nowait()
            self.send(devicedata)
        except Exception as e:
            self._log.debug("Protocol " + name + " process Exception: " +
                            repr(e))

        # release lock, ready for next processing
        self._lock.clear()
Ejemplo n.º 14
0
class SyncedClock_RTC(syncedclock.SyncedClock):

    # since pyb.RTC() is unreliable for reads, do it ourselves directly
    _RTC_BASE = const(0x40002800)
    _RTC_SSR_OFFSET = const(0x28)
    _rtc_ssr_struct = {
        "ss": 0 | uctypes.BFUINT32 | 0 << uctypes.BF_POS | 15 << uctypes.BF_LEN
    }
    _RTC_TR_OFFSET = const(0x00)
    _rtc_tr_struct = {
        "pm":
        0 | uctypes.BFUINT32 | 22 << uctypes.BF_POS | 1 << uctypes.BF_LEN,
        "ht":
        0 | uctypes.BFUINT32 | 20 << uctypes.BF_POS | 2 << uctypes.BF_LEN,
        "hu":
        0 | uctypes.BFUINT32 | 16 << uctypes.BF_POS | 4 << uctypes.BF_LEN,
        "mnt":
        0 | uctypes.BFUINT32 | 12 << uctypes.BF_POS | 3 << uctypes.BF_LEN,
        "mnu":
        0 | uctypes.BFUINT32 | 8 << uctypes.BF_POS | 4 << uctypes.BF_LEN,
        "st": 0 | uctypes.BFUINT32 | 4 << uctypes.BF_POS | 3 << uctypes.BF_LEN,
        "su": 0 | uctypes.BFUINT32 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN
    }
    _RTC_DR_OFFSET = const(0x04)
    _rtc_dr_struct = {
        "yt":
        0 | uctypes.BFUINT32 | 20 << uctypes.BF_POS | 4 << uctypes.BF_LEN,
        "yu":
        0 | uctypes.BFUINT32 | 16 << uctypes.BF_POS | 4 << uctypes.BF_LEN,
        "wdu":
        0 | uctypes.BFUINT32 | 13 << uctypes.BF_POS | 3 << uctypes.BF_LEN,
        "mt":
        0 | uctypes.BFUINT32 | 12 << uctypes.BF_POS | 1 << uctypes.BF_LEN,
        "mu": 0 | uctypes.BFUINT32 | 8 << uctypes.BF_POS | 4 << uctypes.BF_LEN,
        "dt": 0 | uctypes.BFUINT32 | 4 << uctypes.BF_POS | 2 << uctypes.BF_LEN,
        "du": 0 | uctypes.BFUINT32 | 0 << uctypes.BF_POS | 4 << uctypes.BF_LEN
    }

    _RTC_MAX = const(8191)

    # wrap initialiser
    def __init__(self, *args, **kwargs):
        super().__init__(args, kwargs)
        self._uart = None
        self._pps_pin = None
        if kwargs is not None:
            if 'gps_uart' in kwargs:
                self._uart = kwargs['gps_uart']
            if 'pps_pin' in kwargs:
                self._pps_pin = kwargs['pps_pin']

        if (self._uart == None):
            raise ValueError("need a uart for the gps")
        if (self._pps_pin == None):
            raise ValueError("need a pin that gps sends 1pps to us on")

        # we also need the RTC device
        self._rtc = RTC()
        self._pps_event = Event()
        self._rtc_ssr = uctypes.struct(_RTC_BASE + _RTC_SSR_OFFSET,
                                       self._rtc_ssr_struct, uctypes.NATIVE)
        self._rtc_dr = uctypes.struct(_RTC_BASE + _RTC_DR_OFFSET,
                                      self._rtc_dr_struct, uctypes.NATIVE)
        self._pps_rtc = 0
        self._pps_discard = 0
        self._ss_offset = -10000
        self._refclk = (0, 0, 0, 0, 0, 0)

    # try to get some better perf out of this, it's staticish code
    @micropython.native
    def _pps(self, p):
        # grab RTC data when we tick
        # we need to pull this directly out of the registers because we don't want to
        # allocate ram, and the RTC() module does
        self._pps_rtc = self._rtc_ssr.ss
        # need to read DR to nothing to unlock shadow registers
        self._pps_discard = self._rtc_dr.du
        self._pps_event.set()
        return

    async def _wait_gpslock(self):
        try:
            while True:
                if (self._gps.isLocked()):
                    return True
                await asyncio.sleep(1)
        except asyncio.TimeoutError:
            print("syncedclock_rtc: failed to get lock, reinit gps")
        return False

    async def _wait_pps(self):
        try:
            await self._pps_event
            self._pps_event.clear()
            return True
        except asyncio.TimeoutError:
            print("syncedclock_rtc: failed to get pps event in time")
        return False

    # this will now be running in a thread, safe to do things which block
    async def _calibration_loop(self):
        # start RTC
        print("syncedclock_rtc: start rtc")
        self._rtc.init()
        # initalise gps
        self._gps = GPS(self._uart)
        ppsint = ExtInt(self._pps_pin, ExtInt.IRQ_RISING, Pin.PULL_NONE,
                        self._pps)
        ppsint.disable()
        self._pps_event.clear()
        await asyncio.sleep(0)
        while True:
            print("syncedclock_rtc: initalise gps")
            await self._gps.set_auto_messages(['RMC'], 1)
            await self._gps.set_pps_mode(GPS.PPS_Mode.FIX, 42,
                                         GPS.PPS_Polarity.ACTIVE_HIGH, 0)
            print("syncedclock_rtc: waiting for gps lock (30s)")
            res = await asyncio.wait_for(self._wait_gpslock(), 30)
            if (res == False):
                continue
            print(
                "syncedclock_rtc: gps locked, start pps interrupt and wait for pps (3s)"
            )
            #self._pps_pin.irq(trigger=Pin.IRQ_RISING, handler=self._pps)
            ppsint.enable()
            res = await asyncio.wait_for(self._wait_pps(), 3)
            if (res == False):
                print(
                    "syncedclock_rtc: pps signal never recieved, bad wiring?")
                print("syncedclock_rtc: terminating")
                return
            # PPS signal leads GPS data by about half a second or so
            # so the GPS data contains the *previous* second at this point
            # add 1 second and reset RTC
            print("syncedclock_rtc: pps pulse recieved, set RTC clock")
            date = self._gps.date()
            time = self._gps.time()
            # helpfully utime and pyb.RTC use different order in the tuple
            now = utime.localtime(
                utime.mktime((date[2], date[1], date[0], time[0], time[1],
                              time[2], 0, 0)) + 1)
            self._rtc.datetime(
                (now[0], now[1], now[2], 0, now[3], now[4], now[5], 0))
            print("syncedclock_rtc: rtc clock now", self._rtc.datetime())
            await asyncio.sleep(0)
            print("syncedclock_rtc: calibration loop started")
            # ensure we ignore the first cycle
            last_rtc_ss = -1
            # count 32 seconds and calculate the error
            count = 0
            tick_error = 0
            while True:
                # each time we get an PPS event, work out the ticks difference
                res = await asyncio.wait_for(self._wait_pps(), 3)
                if (res == False):
                    print("syncedclock_rtc: lost pps signal, restarting")
                    self._locked = False
                    #self._pps_pin.irq(handler=None)
                    ppsint.disable()
                    break
                rtc_ss = self._pps_rtc
                await asyncio.sleep(0)
                # first pass, just discard the value
                if (last_rtc_ss == -1):
                    last_rtc_ss = rtc_ss
                    continue
                await asyncio.sleep(0)
                count += 1
                # compute the difference in ticks between this and the last
                error = (rtc_ss - last_rtc_ss)
                if (abs(error) > _RTC_MAX - 50):
                    # probably actually rollover problem
                    if (rtc_ss < last_rtc_ss):
                        error = (rtc_ss + _RTC_MAX + 1 - last_rtc_ss)
                    else:
                        error = (rtc_ss - last_rtc_ss + _RTC_MAX + 1)
                await asyncio.sleep(0)
                #print(error)
                tick_error += (error)
                last_rtc_ss = rtc_ss
                # always use the last top of second as current offset if it's not a huge error
                # when locked
                if (self._locked and tick_error > -1 and tick_error < 1):
                    self._ss_offset = rtc_ss
                await asyncio.sleep(0)
                if (count == 32):
                    # if the tick error is +/-1 ticks, it's locked enough
                    # we're only then about 3.81ppm but that's close enough
                    if (self._locked == True
                            and (tick_error > 1 or tick_error < -1)):
                        print("syncedclock_rtc: lost lock")
                        self._locked = False
                    await asyncio.sleep(0)
                    if (self._locked == False
                            and (tick_error <= 1 and tick_error >= -1)):
                        print("syncedclock_rtc: locked with",
                              self._rtc.calibration())
                        # only cache top of second when we enter lock
                        #self._ss_offset = (_RTC_MAX-rtc_ss)
                        self._locked = True
                    await asyncio.sleep(0)
                    if (self._locked == True):
                        # update reference clock point
                        self._refclk = self._rtc.datetime()
                    await asyncio.sleep(0)
                    if (self._locked == False):
                        print("syncedclock_rtc: error now", tick_error)
                    # the total ticks missing should be applied to the calibration
                    # we do this continously so we can ensure the clock is always remaining in sync
                    await asyncio.sleep(0)
                    try:
                        self._rtc.calibration(self._rtc.calibration() +
                                              tick_error)
                    except:
                        print("syncedclock_rtc: error too large, ignoring")
                    # allow us to to be interrupted now
                    await asyncio.sleep(0)
                    #print(rtc.calibration())
                    count = 0
                    tick_error = 0

    def _rtc_to_unixtime(self, rtc_tuple, rtc_offset):
        ts = utime.mktime((
            rtc_tuple[0],  # year
            rtc_tuple[1],  # month
            rtc_tuple[2],  # day
            rtc_tuple[4],  # hour
            rtc_tuple[5],  # minute
            rtc_tuple[6],  # second
            0,
            0)) + 946684800  # weekday and dayofyear are ignored
        tss = (_RTC_MAX - rtc_tuple[7]) + rtc_offset
        if tss >= _RTC_MAX:
            tss -= _RTC_MAX + 1
            ts += 1
        if tss < 0:
            tss += _RTC_MAX + 1
            ts -= 1
        return (ts, tss << 19)

    def now(self):
        if not self._locked:
            return None
        return self._rtc_to_unixtime(self._rtc.datetime(), self._ss_offset)

    def refclk(self):
        if not self._locked:
            return None
        return self._rtc_to_unixtime(self._refclk, self._ss_offset)

    async def start(self):
        super().start()
        loop = asyncio.get_event_loop()
        loop.create_task(self._calibration_loop())
        print("syncedclock_rtc: calibration loop created")
        await asyncio.sleep(0)
        return