def test_calculate_circular_drive_chains(): blocks = [ Block(id='block-1', type='test', data={'ptr1': blox_link('block-2', 'test', True)}), Block(id='block-2', type='test', data={'ptr2': blox_link('block-3', 'test', True)}), Block(id='block-3', type='test', data={'ptr3': blox_link('block-1', 'test', True)}), ] result = block_analysis.calculate_drive_chains(blocks) result = sorted(result, key=lambda v: v['target']) assert result == [ { 'target': 'block-1', 'source': 'block-1', 'intermediate': ['block-3', 'block-2'] }, { 'target': 'block-2', 'source': 'block-2', 'intermediate': ['block-1', 'block-3'] }, { 'target': 'block-3', 'source': 'block-3', 'intermediate': ['block-2', 'block-1'] }, ]
def serialize(block: Block): """ Converts instructions in given Sequence block from dict to line format. """ if 'instructions' in block.data: block.data['instructions'] = [to_line(d) for d in block.data['instructions']]
def parse(block: Block): """ Converts instructions in given Sequence block from line to dict format. """ if 'instructions' in block.data: block.data['instructions'] = [from_line(s, idx + 1) for idx, s in enumerate(block.data['instructions'])]
def test_partial(): # Logged blocks will not include instructions # User input may not include instructions block = Block(id='sequence', type='Sequence', data={}) sequence.parse(block) assert not block.data sequence.serialize(block) assert not block.data
def block_args(app): return Block(id='testobj', serviceId=app['config']['name'], type='TempSensorOneWire', data={ 'value': 12345, 'offset': 20, 'address': 'FF' })
async def post(self, block: Block) -> r200[Block]: """ Validate block data. This checks whether the block can be serialized. It will not be sent to the controller. Tags: Blocks """ block = await self.controller.validate(block) return web.json_response(block.dict())
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_firmware_block(app, client, store): store['alias', 123] = dict() store['4-2', 24] = dict() ctrl = controller.fget(app) assert ctrl._to_firmware_block(Block(id='alias', type='', data={})).nid == 123 assert ctrl._to_firmware_block(Block(nid=840, type='', data={})).nid == 840 assert ctrl._to_firmware_block_identity( BlockIdentity(id='alias')).nid == 123 assert ctrl._to_firmware_block_identity(BlockIdentity(nid=840)).nid == 840 # When both present, NID takes precedence assert ctrl._to_firmware_block(Block(id='alias', nid=444, type='', data={})).nid == 444 with pytest.raises(exceptions.UnknownId): ctrl._to_firmware_block(Block(type='', data={})) with pytest.raises(exceptions.UnknownId): ctrl._to_firmware_block_identity(BlockIdentity())
def make_blocks() -> list[Block]: return [ Block( id='Sensor', type='TempSensorOneWire', serviceId='test', data={ 'address': 'deadbeef', 'offset': delta_temp_qty(0), 'value': temp_qty(20), 'oneWireBusId': blox_link(None), }, ), Block( id='Setpoint', type='SetpointSensorPair', serviceId='test', data={ 'sensorId': blox_link('Sensor', 'TempSensorOneWire'), 'storedSetting': temp_qty(20), 'setting': temp_qty(None), 'value': temp_qty(None), 'valueUnfiltered': temp_qty(None), 'resetFilter': False, 'settingEnabled': True, 'filter': 'FILTER_15s', 'filterThreshold': delta_temp_qty(5), }, ), Block( id='Heat PID', type='Pid', serviceId='test', data={ 'inputValue': temp_qty(0), 'inputSetting': temp_qty(0), 'outputValue': 0, 'outputSetting': 0, 'enabled': False, 'active': True, 'kp': blox_qty(20, '1 / degC'), 'ti': blox_qty(2, 'h'), 'td': blox_qty(0, 's'), 'p': 0, 'i': 0, 'd': 0, 'error': delta_temp_qty(0), 'integral': blox_qty(0, 'delta_degC * hour'), 'derivative': blox_qty(0, 'delta_degC / minute'), 'derivativeFilter': 'FILTER_NONE', 'integralReset': 0, 'boilPointAdjust': delta_temp_qty(0), 'boilMinOutput': 0, 'boilModeActive': False, 'inputId': blox_link('Setpoint', 'SetpointSensorPair'), 'outputId': blox_link('Heat PWM', 'ActuatorPwm'), 'drivenOutputId': blox_link('Heat PWM', 'ActuatorPwm', True), }, ), Block( id='Heat PWM', type='ActuatorPwm', serviceId='test', data={ 'constrainedBy': { 'constraints': [] }, 'desiredSetting': 50, 'setting': 50, 'value': 50, 'actuatorId': blox_link('Heat Actuator', 'DigitalActuator'), 'drivenActuatorId': blox_link( 'Heat Actuator', 'DigitalActuator', True, ), 'enabled': True, 'period': blox_qty(10, 's'), }, ), Block( id='Heat Actuator', type='DigitalActuator', serviceId='test', data={ 'channel': 0, 'constrainedBy': { 'constraints': [ { 'remaining': blox_qty(None, 's'), 'delayedOn': blox_qty(1, 'h'), }, ], }, 'desiredState': 'STATE_ACTIVE', 'state': 'STATE_ACTIVE', 'hwDevice': blox_link('Spark Pins', 'Spark3Pins', True), 'invert': False, }, ), Block( id='Cool PID', type='Pid', serviceId='test', data={ 'inputValue': temp_qty(0), 'inputSetting': temp_qty(0), 'outputValue': 0, 'outputSetting': 0, 'enabled': False, 'active': True, 'kp': blox_qty(20, '1 / degC'), 'ti': blox_qty(2, 'h'), 'td': blox_qty(0, 's'), 'p': 0, 'i': 0, 'd': 0, 'error': delta_temp_qty(0), 'integral': blox_qty(0, 'degC * hour'), 'derivative': blox_qty(0, 'degC / minute'), 'derivativeFilter': 'FILTER_NONE', 'integralReset': 0, 'boilPointAdjust': delta_temp_qty(0), 'boilMinOutput': 0, 'boilModeActive': False, 'inputId': blox_link('Setpoint', 'SetpointSensorPair'), 'outputId': blox_link('Cool PWM', 'ActuatorPwm'), 'drivenOutputId': blox_link('Cool PWM', 'ActuatorPwm', True), }, ), Block( id='Cool PWM', type='ActuatorPwm', serviceId='test', data={ 'constrainedBy': { 'constraints': [{ 'limiting': True, 'balanced': { 'balancerId': blox_link('Balancer', 'Balancer'), 'granted': 10, 'id': 1, }, }, { 'limiting': False, 'max': 100, }], }, 'desiredSetting': 50, 'setting': 50, 'value': 50, 'actuatorId': blox_link('Cool Actuator', 'DigitalActuator'), 'drivenActuatorId': blox_link( 'Cool Actuator', 'DigitalActuator', True, ), 'enabled': True, 'period': blox_qty(10, 's'), }, ), Block( id='Cool Actuator', type='DigitalActuator', serviceId='test', data={ 'channel': 0, 'constrainedBy': { 'constraints': [{ 'remaining': blox_qty(10, 'min'), 'delayedOn': blox_qty(1, 'h'), }, { 'remaining': blox_qty(0, 'min'), 'delayedOff': blox_qty(1, 'h'), }], }, 'desiredState': 'STATE_ACTIVE', 'state': 'STATE_ACTIVE', 'hwDevice': blox_link('Spark Pins', 'Spark3Pins', True), 'invert': False, }, ), Block( id='Spark Pins', type='Spark3Pins', serviceId='test', data={ 'enableIoSupply12V': True, 'enableIoSupply5V': True, 'channels': [], 'soundAlarm': False, 'voltage12': 12, 'voltage5': 5, }, ), Block( id='DisplaySettings', type='DisplaySettings', serviceId='test', data={ 'brightness': 0, 'name': 'Suggestive Sensors', 'tempUnit': 'TEMP_CELSIUS', 'timeZone': 'UTC0', 'widgets': [ { 'color': '4169e1', 'name': 'Sensor 1', 'pos': 1, 'tempSensor': blox_link('TempSensorOneWire-1', 'TempSensorInterface'), }, ], }, ), ]
async def _patch(self, topic: str, msg: dict): block = Block(**msg) if block.serviceId == self.name: await self.controller.patch_block(block)