예제 #1
0
    def _to_block(self, block: FirmwareBlock, find_sid=True) -> Block:
        block = Block(**block.dict(), id=None, serviceId=self._name)

        block.id = self._find_sid(block.nid, block.type) if find_sid else None
        resolve_data_ids(block.data, self._find_sid)

        # Special case, where the API data format differs from proto-ready format
        if block.type == const.SEQUENCE_BLOCK_TYPE:
            sequence.serialize(block)

        return block
async def test_to_block(app, client, store):
    store['alias', 123] = dict()
    store['4-2', 24] = dict()

    ctrl = controller.fget(app)

    assert ctrl._to_block(FirmwareBlock(nid=123, type='',
                                        data={})).id == 'alias'

    # Service ID not found: create placeholder
    generated = ctrl._to_block(FirmwareBlock(nid=456, type='', data={}))
    assert generated.id.startswith(const.GENERATED_ID_PREFIX)
예제 #3
0
    async def clear_blocks(self) -> list[BlockIdentity]:
        """
        Remove all user-created blocks on the controller.
        System blocks will not be removed, but the display settings
        will be reset.

        Returns:
            list[BlockIdentity]:
                The ids of all removed blocks.
        """
        async with self._execute('Remove all blocks'):
            await self._cmder.clear_blocks()
            self._store.clear()
            await self._cmder.write_block(
                FirmwareBlock(
                    nid=const.DISPLAY_SETTINGS_NID,
                    type='DisplaySettings',
                    data={},
                ))
            ids = [
                BlockIdentity(id=sid, nid=nid, serviceId=self._name)
                for (sid, nid) in block_cache.keys(self.app)
                if nid >= const.USER_NID_START
            ]
            block_cache.delete_all(self.app)
            return ids
 async def _sync_time(self):
     now = datetime.now()
     ticks_block = await self.commander.write_block(
         FirmwareBlock(nid=const.SYSTIME_NID,
                       type='Ticks',
                       data={'secondsSinceEpoch': int(now.timestamp())}))
     ms = ticks_block.data['millisSinceBoot']
     uptime = timedelta(milliseconds=ms)
     LOGGER.info(f'System uptime: {uptime}')
예제 #5
0
 async def _to_block(
     self,
     payload: EncodedPayload,
     opts: codec.DecodeOpts,
 ) -> FirmwareBlock:
     enc_id = (payload.blockType, payload.subtype)
     enc_content = payload.content
     (blockType,
      subtype), data = await self._codec.decode(enc_id, enc_content, opts)
     return FirmwareBlock(
         nid=payload.blockId,
         type=join_type(blockType, subtype),
         data=data,
     )
예제 #6
0
    def _to_firmware_block(self, block: Block, find_nid=True) -> FirmwareBlock:
        sid = block.id
        nid = block.nid

        if nid is None:
            try:
                nid = self._store.right_key(sid) if find_nid else 0
            except KeyError:
                raise exceptions.UnknownId(
                    f'No numeric ID matching [sid={block.id},type={block.type}] found in store'
                )

        block = FirmwareBlock(nid=nid, type=block.type, data=block.data)

        # Special case, where the API data format differs from proto-ready format
        if block.type == const.SEQUENCE_BLOCK_TYPE:
            sequence.parse(block)

        resolve_data_ids(block.data, self._find_nid)
        return block
def default_blocks() -> dict[int, FirmwareBlock]:
    return {
        block.nid: block
        for block in [
            FirmwareBlock(
                nid=const.SYSINFO_NID,
                type='SysInfo',
                data={'deviceId': 'FACADE'},
            ),
            FirmwareBlock(
                nid=const.SYSTIME_NID,
                type='Ticks',
                data={
                    'millisSinceBoot': 0,
                    'secondsSinceEpoch': 0,
                },
            ),
            FirmwareBlock(
                nid=const.ONEWIREBUS_NID,
                type='OneWireBus',
                data={},
            ),
            FirmwareBlock(
                nid=const.WIFI_SETTINGS_NID,
                type='WiFiSettings',
                data={},
            ),
            FirmwareBlock(
                nid=const.TOUCH_SETTINGS_NID,
                type='TouchSettings',
                data={},
            ),
            FirmwareBlock(
                nid=const.DISPLAY_SETTINGS_NID,
                type='DisplaySettings',
                data={'timeZone': 'Africa/Casablanca'},
            ),
            FirmwareBlock(
                nid=const.SPARK_PINS_NID,
                type='Spark3Pins',
                data={
                    'channels': [
                        {
                            'id': 1
                        },
                        {
                            'id': 2
                        },
                        {
                            'id': 3
                        },
                        {
                            'id': 4
                        },
                        {
                            'id': 5
                        },
                    ]
                },
            ),
        ]
    }
    async def write(self, request_b64: Union[str, bytes]):  # pragma: no cover
        try:
            self.update_ticks()
            _, dict_content = await self._codec.decode(
                (codec.REQUEST_TYPE, None),
                request_b64,
            )
            request = EncodedRequest(**dict_content)
            payload = request.payload
            if payload:
                (in_blockType, _), in_content = await self._codec.decode(
                    (payload.blockType, payload.subtype),
                    payload.content,
                )
            else:
                in_blockType = 0
                in_content = None

            response = EncodedResponse(msgId=request.msgId,
                                       error=ErrorCode.OK,
                                       payload=[])

            if self.next_error:
                error = self.next_error.pop(0)
                if error is None:
                    return  # No response at all
                else:
                    response.error = error

            elif request.opcode in [
                    Opcode.NONE,
                    Opcode.VERSION,
            ]:
                await self.welcome()

            elif request.opcode in [Opcode.BLOCK_READ, Opcode.STORAGE_READ]:
                block = self._blocks.get(payload.blockId)
                if not block:
                    response.error = ErrorCode.INVALID_BLOCK_ID
                else:
                    (blockType, subtype), content = await self._codec.encode(
                        (block.type, None),
                        block.data,
                    )

                    response.payload = [
                        EncodedPayload(blockId=block.nid,
                                       blockType=blockType,
                                       subtype=subtype,
                                       content=content)
                    ]

            elif request.opcode in [
                    Opcode.BLOCK_READ_ALL,
                    Opcode.STORAGE_READ_ALL,
            ]:
                for block in self._blocks.values():
                    (blockType, subtype), content = await self._codec.encode(
                        (block.type, None),
                        block.data,
                    )
                    response.payload.append(
                        EncodedPayload(
                            blockId=block.nid,
                            blockType=blockType,
                            subtype=subtype,
                            content=content,
                        ))

            elif request.opcode == Opcode.BLOCK_WRITE:
                block = self._blocks.get(payload.blockId)
                if not block:
                    response.error = ErrorCode.INVALID_BLOCK_ID
                elif not in_content:
                    response.error = ErrorCode.INVALID_BLOCK
                elif in_blockType != block.type:
                    response.error = ErrorCode.INVALID_BLOCK_TYPE
                else:
                    block.data = in_content
                    (blockType, subtype), data = await self._codec.encode(
                        (block.type, None),
                        block.data,
                    )
                    response.payload = [
                        EncodedPayload(blockId=block.nid,
                                       blockType=blockType,
                                       subtype=subtype,
                                       data=data)
                    ]

            elif request.opcode == Opcode.BLOCK_CREATE:
                nid = payload.blockId
                block = self._blocks.get(nid)
                if block:
                    response.error = ErrorCode.BLOCK_NOT_CREATABLE
                elif nid > 0 and nid < const.USER_NID_START:
                    response.error = ErrorCode.BLOCK_NOT_CREATABLE
                elif not in_content:
                    response.error = ErrorCode.INVALID_BLOCK
                else:
                    nid = nid or next(self._id_counter)
                    block = FirmwareBlock(
                        nid=nid,
                        type=in_blockType,
                        data=in_content,
                    )
                    self._blocks[nid] = block
                    (blockType, subtype), content = await self._codec.encode(
                        (block.type, None),
                        block.data,
                    )
                    response.payload = [
                        EncodedPayload(
                            blockId=block.nid,
                            blockType=blockType,
                            subtype=subtype,
                            content=content,
                        )
                    ]

            elif request.opcode == Opcode.BLOCK_DELETE:
                nid = payload.blockId
                block = self._blocks.get(nid)
                if not block:
                    response.error = ErrorCode.INVALID_BLOCK_ID
                elif nid < const.USER_NID_START:
                    response.error = ErrorCode.BLOCK_NOT_DELETABLE
                else:
                    del self._blocks[nid]

            elif request.opcode == Opcode.BLOCK_DISCOVER:
                # Always return spark pins when discovering blocks
                block = self._blocks[const.SPARK_PINS_NID]
                (blockType, subtype), content = await self._codec.encode(
                    (block.type, None),
                    block.data,
                )
                response.payload = [
                    EncodedPayload(
                        blockId=block.nid,
                        blockType=blockType,
                        subtype=subtype,
                        content=content,
                    )
                ]

            elif request.opcode == Opcode.REBOOT:
                self._start_time = datetime.now()
                self.update_ticks()

            elif request.opcode == Opcode.CLEAR_BLOCKS:
                self._blocks = default_blocks()
                self.update_ticks()

            elif request.opcode == Opcode.CLEAR_WIFI:
                self._blocks[const.WIFI_SETTINGS_NID].data.clear()

            elif request.opcode == Opcode.FACTORY_RESET:
                self._blocks = default_blocks()
                self.update_ticks()

            elif request.opcode == Opcode.FIRMWARE_UPDATE:
                pass

            else:
                response.error = ErrorCode.INVALID_OPCODE

            _, response_b64 = await self._codec.encode(
                (codec.RESPONSE_TYPE, None), response.dict())
            await self._on_data(response_b64)

        except Exception as ex:
            LOGGER.error(strex(ex))
            raise ex