示例#1
0
def mqtt_can_messages_not_supported():
    return [
        (Mqtt.message('NODE/F0/DISCOVERY/0/QUERY', ''),
         can.Message(arbitration_id=(Message.DISCOVERY | Node.can_encode(0xF0)
                                     | Device.can_encode(9) | Operation.STATE),
                     data=None)),
        (Mqtt.message('NODE/F0/PWM_INPUT/9/SET', '1013'),
         can.Message(arbitration_id=(Message.PWM_INPUT | Node.can_encode(0xF0)
                                     | Device.can_encode(9) | Operation.STATE),
                     data=pack('<H', 1013))),
    ]
示例#2
0
def mqtt_can_messages():
    return [
        (Mqtt.message('NODE/69/PING/3/QUERY', '0xDEAD'),
         can.Message(arbitration_id=(Message.PING | Node.can_encode(0x69)
                                     | Device.can_encode(3) | Operation.QUERY),
                     data=pack('<H', 0xDEAD))),
        (Mqtt.message(
            'NODE/89/DATETIME/7/SET',
            json.dumps({
                "year": 2020,
                "month": 6,
                "day": 16,
                "hour": 1,
                "minute": 23,
                "second": 45,
                "dayofweek": 2
            })),
         can.Message(arbitration_id=(Message.DATETIME | Node.can_encode(0x89)
                                     | Device.can_encode(7) | Operation.SET),
                     data=pack('<HBBBBBB', 2020, 6, 16, 1, 23, 45, 2))),
        (Mqtt.message(
            'NODE/89/KEY/17/QUERY',
            json.dumps({
                "keycode": 0x45,
                "action": KeyAction.UP.name,
                "ar_count": 5,
                "mp_count": 3
            })),
         can.Message(
             arbitration_id=(Message.KEY | Node.can_encode(0x89)
                             | Device.can_encode(0x17) | Operation.QUERY),
             data=pack('<BBBB', 0x45, 2, 5, 3))),
        (Mqtt.message(
            'NODE/D4/DIGITAL_OUTPUT/9/SET',
            bytes(json.dumps({"cmd": DigitalOutput.ON.name}), 'utf-8')),
         can.Message(
             arbitration_id=(Message.DIGITAL_OUTPUT | Node.can_encode(0xD4)
                             | Device.can_encode(9) | Operation.SET),
             data=pack('<B', DigitalOutput.ON.value))),
        (Mqtt.message(
            'NODE/34/COVER/2/SET',
            bytes(json.dumps({
                "cmd": Cover.OPEN.name,
                "position": 30
            }), 'utf-8')),
         can.Message(arbitration_id=(Message.COVER | Node.can_encode(0x34)
                                     | Device.can_encode(2) | Operation.SET),
                     data=pack('<BB', Cover.OPEN.value, 30))),
    ]
示例#3
0
def can2mqtt_messages_valid():
    return [
        (Mqtt.message('NODE/69/DUST/1/STATE',
            bytes(json.dumps({"pm2.5": 5.5, "pm10": 10.1}), 'utf-8')),
         can.Message(arbitration_id = (Message.DUST |
                 Node.can_encode(0x69) | Device.can_encode(0x01) | Operation.STATE),
             data=pack('<ff', 5.5, 10.1))),
    ]
示例#4
0
def can2mqtt_messages_invalid():
    return [
        (Mqtt.message('NODE/69/DUST/0/SET',
            bytes(json.dumps({"pm2.5": 0, "pm10": 0}), 'utf-8')),
         can.Message(arbitration_id = (Message.DUST |
                 Node.can_encode(0x69) | Device.can_encode(0x01) | Operation.SET),
             data=pack('<ff', 0.001, 0.001))),
    ]
示例#5
0
def mqtt_can_messages():
    pca963x_single_channel_msgs = []
    for op in [Operation.SET]:
        pca963x_single_channel_msgs.append(
            (Mqtt.message('NODE/69/PCA963x/3/AMBER0/{}'.format(op.name),
                          bytes(PCA963x.Command.TOGGLE.name, 'utf-8')),
             can.Message(arbitration_id = (Message.PCA963x |
                     Node.can_encode(0x69) | Device.can_encode(0x03) | op),
                 data=pack('<BB', PCA963x.Channel.AMBER0, PCA963x.Command.TOGGLE)))
        )
        pca963x_single_channel_msgs.append(
            (Mqtt.message('NODE/69/PCA963x/3/AMBER0/{}'.format(op.name),
                          bytes('123', 'utf-8')),
             can.Message(arbitration_id = (Message.PCA963x |
                     Node.can_encode(0x69) | Device.can_encode(0x03) | op),
                 data=pack('<BBB', PCA963x.Channel.AMBER0, PCA963x.Command.PWM, 123)))
        )

    return pca963x_single_channel_msgs
示例#6
0
def mqtt2can(mqtt_msg):
    """ Convert MQTT message into CAN frame
    """
    match = re.match(r'^NODE/(?P<node>[0-9a-fA-F]+)/'
            '(?P<msg>[^/]+)/(?P<dev>[0-9a-fA-F]+)/'
            '((?P<extra>\S+)/)?(?P<op>[^/]+)$',
            mqtt_msg.topic)
    if not match:
        raise HomeCanMessageError('bad mqtt message')
    ## base format seems ok, extract parts for further processing
    node = match.group('node')
    dev = match.group('dev')
    try:
        msg = Message.mqtt_decode(match.group('msg'))
    except KeyError:
        raise HomeCanMessageError('wrong mqtt message type')
    op = Operation[match.group('op')]

    if op not in [Operation.QUERY, Operation.SET, Operation.RESET]:
        raise HomeCanBridgingForbidden('{} may not be translated from MQTT into CAN'.format(op.name))

    ## FIXME should we translate all messages back and forth?
    #if op not in [HC_MESSAGE.QUERY, HC_MESSAGE.SET]:
    #    raise HomeCanMessageError('wrong mqtt message type')`

    ## calculate CAN extended id
    can_eid = msg | Node.mqtt2can(node) | Device.mqtt2can(dev) | op
    ## prepare frame data based on msg type
    if msg == Message.PING:
        can_frame = _mqtt2can_ping(can_eid, msg, mqtt_msg.payload)
    elif msg == Message.DATETIME:
        can_frame = _mqtt2can_datetime(can_eid, msg, mqtt_msg.payload)
    elif msg == Message.KEY:
        can_frame = _mqtt2can_key(can_eid, msg, mqtt_msg.payload)
    elif msg in [Message.TEMPERATURE, Message.RHUMIDITY,
            Message.ILLUMINANCE, Message.PRESSURE]:
        can_frame = _mqtt2can_simple_sensor(can_eid, msg, mqtt_msg.payload)
    elif msg in [Message.DUST]:
        from can2mqtt.bridge_dust import _mqtt2can_dust
        can_frame = _mqtt2can_dust(can_eid, msg, mqtt_msg.payload)
    elif msg == Message.DIGITAL_OUTPUT:
        can_frame = _mqtt2can_digital_output(can_eid, msg, mqtt_msg.payload)
    elif msg == Message.PCA963x:
        from can2mqtt.bridge_pca963x import _mqtt2can_pca963x
        extra = match.group('extra')
        can_frame = _mqtt2can_pca963x(can_eid, msg, extra, mqtt_msg.payload)
    elif msg == Message.COVER:
        can_frame = _mqtt2can_cover(can_eid, msg, mqtt_msg.payload)
    else:
        raise HomeCanMessageNotSupported('mqtt message {} not yet supported'.
                format(msg.name))
    
    return can_frame
示例#7
0
def _can2mqtt_ping(can_frame):
    """ Parse HomeCan CAN frame containing ping message
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    op = Operation.can_decode(can_frame.arbitration_id)
    if msg == Message.PING:
        raw_payload, = unpack('<H', can_frame.data)
        payload = '0x{:4X}'.format(raw_payload)
    else:
        raise HomeCanMessageNotSupported('can message {} type not '
                'supported by {}'.format(msg.name,
                    sys._getframe().f_code.co_name))
    return Mqtt.message('NODE/{:X}/{}/{:X}/{}'.format(
                node_id, msg.name, device_id, op.name),
            payload)
示例#8
0
def _can2mqtt_digital_output(can_frame):
    """ Parse HomeCan CAN frame containing digital output message
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    op = Operation.can_decode(can_frame.arbitration_id)
    if msg == Message.DIGITAL_OUTPUT:
        cmd_raw, = unpack('<B', can_frame.data)
        cmd = DigitalOutput(cmd_raw).name
        payload = bytes(json.dumps({"state": cmd}), 'utf-8')
    else:
        raise HomeCanMessageNotSupported('can message {} type not '
                'supported by {}'.format(msg.name,
                    sys._getframe().f_code.co_name))
    return Mqtt.message('NODE/{:X}/{}/{:X}/{}'.format(
                node_id, msg.name, device_id, op.name),
            payload)
示例#9
0
def _can2mqtt_cover(can_frame):
    """ Parse HomeCan CAN frame containing cover message
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    op = Operation.can_decode(can_frame.arbitration_id)
    if msg == Message.COVER:
        cmd_raw, position, = unpack('<BB', can_frame.data)
        cmd = Cover(cmd_raw).name
        payload = json.dumps({"cmd": cmd, "position": position})
    else:
        raise HomeCanMessageNotSupported('can message {} type not '
                'supported by {}'.format(msg.name,
                    sys._getframe().f_code.co_name))
    return Mqtt.message('NODE/{:X}/{}/{:X}/{}'.format(
                node_id, msg.name, device_id, op.name),
            payload)
示例#10
0
def _can2mqtt_datetime(can_frame):
    """ Parse HomeCan CAN frame containing date/time message
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    op = Operation.can_decode(can_frame.arbitration_id)
    if msg == Message.DATETIME:
        year, month, day, hour, minute, second, weekday = unpack('<HBBBBBB', can_frame.data)
        payload = json.dumps({"year": year, "month": month, "day": day,
                             "hour": hour, "minute": minute, "second": second,
                             "dayofweek": weekday})
    else:
        raise HomeCanMessageNotSupported('can message {} type not '
                'supported by {}'.format(msg.name,
                    sys._getframe().f_code.co_name))
    return Mqtt.message('NODE/{:X}/{}/{:X}/{}'.format(
                node_id, msg.name, device_id, op.name),
            payload)
示例#11
0
def _can2mqtt_key(can_frame):
    """ Parse HomeCan CAN frame containing key message
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    op = Operation.can_decode(can_frame.arbitration_id)
    if msg == Message.KEY:
        keycode, key_action_raw, ar_count, mp_count = unpack('<BBBB', can_frame.data)
        key_action = KeyAction(key_action_raw).name
        payload = json.dumps({"keycode": keycode, "action": key_action,
                             "ar_count": ar_count, "mp_count": mp_count})
    else:
        raise HomeCanMessageNotSupported('can message {} type not '
                'supported by {}'.format(msg.name,
                    sys._getframe().f_code.co_name))
    return Mqtt.message('NODE/{:X}/{}/{:X}/{}'.format(
                node_id, msg.name, device_id, op.name),
            payload)
示例#12
0
def _can2mqtt_simple_sensor_report(can_frame):
    """ Parse HomeCan CAN frame containing simple sensor message
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    op = Operation.can_decode(can_frame.arbitration_id)
    if msg in [Message.TEMPERATURE, Message.RHUMIDITY]:
        raw_payload, = unpack('<f', can_frame.data)
        payload = '{:0.2f}'.format(raw_payload)
    elif msg in [Message.ILLUMINANCE, Message.PRESSURE]:
        raw_payload, = unpack('<H', can_frame.data)
        payload = '{:d}'.format(raw_payload)
    else:
        raise HomeCanMessageNotSupported('can message {} type not '
                'supported by {}'.format(msg.name,
                    sys._getframe().f_code.co_name))
    return Mqtt.message('NODE/{:X}/{}/{:X}/{}'.format(
                node_id, msg.name, device_id, op.name),
            payload)
示例#13
0
def _can2mqtt_dust(can_frame):
    """ Parse HomeCan CAN frame containing data from dust sensors
        data[0-3] - data: pm2.5
        data[4-7] - data: pm10
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    ##
    op = Operation.can_decode(can_frame.arbitration_id)
    if op != Operation.STATE:
        raise HomeCanBridgingForbidden('operation {} not supported for {} '
                                       'messages'.format(op.name, msg.name))
    ##
    pm2_5, pm10, = unpack('<ff', can_frame.data)
    ##
    return Mqtt.message(
        'NODE/{:X}/{}/{:X}/{}'.format(node_id, msg.name, device_id,
                                      Operation.STATE.name),
        bytes(json.dumps({
            "pm2.5": round(pm2_5, 2),
            "pm10": round(pm10, 2)
        }), 'utf-8'))
示例#14
0
def _can2mqtt_pca963x(can_frame):
    """ Parse HomeCan CAN frame containing commands for PCA963x modules
        data[0] - channel: red, green, blue, amber, rgb, rgba
        data[1] - command: set, brightness, sleep
        data[2-x] - color, brightness, time, etc.
    """
    node_id = Node.can_decode(can_frame.arbitration_id)
    device_id = Device.can_decode(can_frame.arbitration_id)
    msg = Message.can_decode(can_frame.arbitration_id)
    op = Operation.can_decode(can_frame.arbitration_id)
    ##
    ch = PCA963x.Channel(can_frame.data[0])
    cmd = PCA963x.Command(can_frame.data[1])
    ##
    if ch in [
            PCA963x.Channel.RED0, PCA963x.Channel.GREEN0,
            PCA963x.Channel.BLUE0, PCA963x.Channel.AMBER0,
            PCA963x.Channel.RED1, PCA963x.Channel.GREEN1,
            PCA963x.Channel.BLUE1, PCA963x.Channel.AMBER1
    ]:
        ##
        if cmd in [
                PCA963x.Command.OFF, PCA963x.Command.ON, PCA963x.Command.TOGGLE
        ]:
            payload = cmd.name
            return Mqtt.message(
                'NODE/{:X}/{}/{:X}/{}/{}/{}'.format(node_id, msg.name,
                                                    device_id, ch.name,
                                                    'SWITCH', op.name),
                payload)
        elif cmd == PCA963x.Command.PWM_VALUE:
            payload = '{:X}'.format(can_frame.data[2])
            return Mqtt.message(
                'NODE/{:X}/{}/{:X}/{}/{}/{}'.format(node_id, msg.name,
                                                    device_id, ch.name,
                                                    cmd.name, op.name),
                payload)
        elif cmd == PCA963x.Command.PWM_BRIGHTNESS:
            payload = '{:X}'.format(can_frame.data[2])
            return Mqtt.message(
                'NODE/{:X}/{}/{:X}/{}/{}/{}'.format(node_id, msg.name,
                                                    device_id, ch.name,
                                                    cmd.name, op.name),
                payload)
        elif cmd == PCA963x.Command.PWM_SLEEP:
            payload = '{:X}'.format(can_frame.data[2] +
                                    (can_frame.data[3] << 8))
            return Mqtt.message(
                'NODE/{:X}/{}/{:X}/{}/{}/{}'.format(node_id, msg.name,
                                                    device_id, ch.name,
                                                    cmd.name, op.name),
                payload)
    elif ch in [PCA963x.Channel.RGB0, PCA963x.Channel.RGB1]:
        ##
        if cmd == PCA963x.Command.PWM_VALUE:
            payload = '{:X},{:X},{:X}'.format(can_frame.data[2],
                                              can_frame.data[3],
                                              can_frame.data[4])
            return Mqtt.message(
                'NODE/{:X}/{}/{:X}/{}/{}/{}'.format(node_id, msg.name,
                                                    device_id, ch.name,
                                                    cmd.name, op.name),
                payload)
        elif cmd == PCA963x.Command.PWM_BRIGHTNESS:
            payload = '{:X}'.format(can_frame.data[2])
            return Mqtt.message(
                'NODE/{:X}/{}/{:X}/{}/{}/{}'.format(node_id, msg.name,
                                                    device_id, ch.name,
                                                    cmd.name, op.name),
                payload)
        elif cmd == PCA963x.Command.PWM_SLEEP:
            payload = '{:X}'.format(can_frame.data[2] +
                                    (can_frame.data[3] << 8))
            return Mqtt.message(
                'NODE/{:X}/{}/{:X}/{}/{}/{}'.format(node_id, msg.name,
                                                    device_id, ch.name,
                                                    cmd.name, op.name),
                payload)

    raise HomeCanMessageNotSupported('pca963x message configuration not '
                                     'supported by {}'.format(
                                         sys._getframe().f_code.co_name))
示例#15
0
def can_message_discovery():
    return can.Message(
        arbitration_id=(Message.DISCOVERY | Node.can_encode(0xF0)
                        | Device.can_encode(9) | Operation.STATE),
        data=None)
示例#16
0
def test_device_mqtt2can(hc_devices):
    for mqtt, can in hc_devices:
        assert Device.mqtt2can(mqtt) == can
示例#17
0
def can_mqtt_messages():
    return [
        (Mqtt.message('NODE/69/PING/3/EVENT', '0xDEAD'),
         can.Message(arbitration_id=(Message.PING | Node.can_encode(0x69)
                                     | Device.can_encode(3) | Operation.EVENT),
                     data=pack('<H', 0xDEAD))),
        (Mqtt.message(
            'NODE/89/DATETIME/7/STATE',
            json.dumps({
                "year": 2020,
                "month": 6,
                "day": 16,
                "hour": 1,
                "minute": 23,
                "second": 45,
                "dayofweek": 2
            })),
         can.Message(arbitration_id=(Message.DATETIME | Node.can_encode(0x89)
                                     | Device.can_encode(7) | Operation.STATE),
                     data=pack('<HBBBBBB', 2020, 6, 16, 1, 23, 45, 2))),
        (Mqtt.message(
            'NODE/89/KEY/17/EVENT',
            json.dumps({
                "keycode": 0x45,
                "action": KeyAction.UP.name,
                "ar_count": 5,
                "mp_count": 3
            })),
         can.Message(
             arbitration_id=(Message.KEY | Node.can_encode(0x89)
                             | Device.can_encode(0x17) | Operation.EVENT),
             data=pack('<BBBB', 0x45, 2, 5, 3))),
        (Mqtt.message('NODE/69/TEMPERATURE/3/STATE', '12.34'),
         can.Message(
             arbitration_id=(Message.TEMPERATURE | Node.can_encode(0x69)
                             | Device.can_encode(3) | Operation.STATE),
             data=pack('<f', 12.34))),
        (Mqtt.message('NODE/12/RHUMIDITY/7/STATE', '54.32'),
         can.Message(arbitration_id=(Message.RHUMIDITY | Node.can_encode(0x12)
                                     | Device.can_encode(7) | Operation.STATE),
                     data=pack('<f', 54.32))),
        (Mqtt.message('NODE/F0/ILLUMINANCE/9/STATE', '127'),
         can.Message(
             arbitration_id=(Message.ILLUMINANCE | Node.can_encode(0xF0)
                             | Device.can_encode(9) | Operation.STATE),
             data=pack('<H', 127))),
        (Mqtt.message('NODE/F0/PRESSURE/9/STATE', '1013'),
         can.Message(arbitration_id=(Message.PRESSURE | Node.can_encode(0xF0)
                                     | Device.can_encode(9) | Operation.STATE),
                     data=pack('<H', 1013))),
        (Mqtt.message(
            'NODE/D4/DIGITAL_OUTPUT/9/STATE',
            bytes(json.dumps({"state": DigitalOutput.ON.name}), 'utf-8')),
         can.Message(
             arbitration_id=(Message.DIGITAL_OUTPUT | Node.can_encode(0xD4)
                             | Device.can_encode(9) | Operation.STATE),
             data=pack('<B', DigitalOutput.ON.value))),
        (Mqtt.message('NODE/34/COVER/2/STATE',
                      json.dumps({
                          "cmd": Cover.OPEN.name,
                          "position": 30
                      })),
         can.Message(arbitration_id=(Message.COVER | Node.can_encode(0x34)
                                     | Device.can_encode(2) | Operation.STATE),
                     data=pack('<BB', Cover.OPEN.value, 30))),
    ]
示例#18
0
def test_device_can2mqtt(hc_devices):
    for mqtt, can in hc_devices:
        assert Device.can2mqtt(can) == mqtt