class Sensor(Device): delay_validator = validators.DecimalValidator(name='delay', min_value=0.2) max_delay_validator = validators.DecimalValidator(name='max_delay') config_mode_validator = validators.BooleanValidator(name='config_mode') def __init__(self, delay=10, max_delay=0, config_mode=False, **kwargs): super().__init__(**kwargs) self.delay = self.delay_validator(delay) self.max_delay = self.max_delay_validator(max_delay) self.config_mode = self.config_mode_validator(config_mode) self.sensor_previous_value = None self.sensor_set_state_time = 0 async def setup(self): self.set_state('delay', self.delay) self.set_state('max_delay', self.max_delay) self.set_state('config_mode', json.dumps(self.config_mode)) async def loop(self): while True: await self.set_value() await asyncio.sleep(float(self.delay)) async def message_received(self, sender=None, topic=None, payload=None): if self.config_mode and bool(payload): if topic == 'delay': self.delay = self.delay_validator(payload) self.set_state('delay', self.delay) if topic == 'max_delay': self.max_delay = self.max_delay_validator(payload) self.set_state('max_delay', self.max_delay) async def set_value(self): value = await self.get_value() value = self.clean_value(value) if self.is_changed(value, self.sensor_previous_value): self.sensor_set_state_time = time.time_ns() self.set_state('value', value) else: now = time.time_ns() if (now - self.sensor_set_state_time ) // 1000000000 >= self.max_delay: self.sensor_set_state_time = time.time_ns() self.set_state('value', value) self.sensor_previous_value = value async def get_value(self): raise NotImplementedError() def clean_value(self, value): return value def is_changed(self, value, previous_value): return not (value == previous_value)
def test_min_value(self): validator = validators.DecimalValidator(name='delay', min_value=2) self.assertEqual(validator(2), Decimal('2')) with self.assertRaises(ValidationError) as ctx: validator(1.99) self.assertEqual(ctx.exception.message, 'Ensure delay is greater than or equal to 2.000000') validator = validators.DecimalValidator(name='delay', min_value=0.2) self.assertEqual(validator(0.2), Decimal('0.2')) with self.assertRaises(ValidationError) as ctx: validator(0.199) self.assertEqual(ctx.exception.message, 'Ensure delay is greater than or equal to 0.200000')
def __init__(self, scale=1, precision=0, change_margin=0, unit_of_measurement='', **kwargs): super().__init__(**kwargs) self.scale = self.scale_validator(scale) self.precision = self.precision_validator(precision) self.change_margin_validator = validators.DecimalValidator( name='change_margin', precision=self.precision) self.change_margin = self.change_margin_validator(change_margin) self.unit_of_measurement = unit_of_measurement self.value_validator = validators.DecimalValidator( name='value', precision=self.precision)
def test_max_value(self): validator = validators.DecimalValidator(name='delay', max_value=2) self.assertEqual(validator(2), Decimal('2')) with self.assertRaises(ValidationError) as ctx: validator(2.01) self.assertEqual(ctx.exception.message, 'Ensure delay is less than or equal to 2.000000')
def test_precision(self): validator = validators.DecimalValidator(name='delay', precision=2) self.assertEqual(validator(1.2), Decimal('1.2')) self.assertEqual(validator(1.23), Decimal('1.23')) self.assertEqual(validator(1.234), Decimal('1.23')) validator = validators.DecimalValidator(name='delay', precision=0) self.assertEqual(validator(-0.125), Decimal('0')) self.assertEqual(validator(Decimal('-0.125')), Decimal('0')) self.assertEqual(str(validator(-0.125)), '0') self.assertEqual(str(validator('-0.125')), '0') self.assertEqual(str(validator(Decimal('-0.125'))), '0') self.assertEqual(validator(54321.2), Decimal('54321')) self.assertEqual(validator(54321.23), Decimal('54321')) self.assertEqual(validator(54321.234), Decimal('54321')) validator = validators.DecimalValidator(name='delay', precision=-2) self.assertEqual(validator(1550), Decimal('1600')) self.assertEqual(validator(54321.2), Decimal('54300')) self.assertEqual(validator(54321.23), Decimal('54300')) self.assertEqual(validator(54321.234), Decimal('54300'))
class NumericSensor(Sensor): scale_validator = validators.DecimalValidator(name='scale') precision_validator = validators.IntegerValidator(name='precision') def __init__(self, scale=1, precision=0, change_margin=0, unit_of_measurement='', **kwargs): super().__init__(**kwargs) self.scale = self.scale_validator(scale) self.precision = self.precision_validator(precision) self.change_margin_validator = validators.DecimalValidator( name='change_margin', precision=self.precision) self.change_margin = self.change_margin_validator(change_margin) self.unit_of_measurement = unit_of_measurement self.value_validator = validators.DecimalValidator( name='value', precision=self.precision) async def setup(self): await super().setup() self.set_state('scale', self.scale) self.set_state('precision', self.precision) self.set_state('change_margin', self.change_margin) self.set_state('unit_of_measurement', self.unit_of_measurement) def clean_value(self, value): return self.value_validator(Decimal(value) * self.scale) def is_changed(self, value, previous_value): if previous_value is None: return True if self.change_margin == 0: return not (value == previous_value) return bool(abs(value - previous_value) >= self.change_margin) async def message_received(self, sender=None, topic=None, payload=None): await super().message_received(sender=sender, topic=topic, payload=payload) if self.config_mode and bool(payload): if topic == 'scale': self.scale = self.scale_validator(payload) self.set_state('scale', self.scale) if topic == 'precision': self.precision = self.precision_validator(payload) self.set_state('precision', self.precision) if topic == 'change_margin': self.change_margin = self.change_margin_validator(payload) self.set_state('change_margin', self.change_margin)
def test_simple(self): validator = validators.DecimalValidator(name='delay') self.assertEqual(validator(0), Decimal('0')) self.assertEqual(validator(-0), Decimal('0')) self.assertEqual(validator(0.1), Decimal('0.1')) self.assertEqual(validator(1), Decimal('1')) self.assertEqual(validator(1.2), Decimal('1.2')) self.assertEqual(validator(-1.2), Decimal('-1.2')) self.assertEqual(validator('0'), Decimal('0')) self.assertEqual(validator('-0'), Decimal('0')) self.assertEqual(validator('0.1'), Decimal('0.1')) self.assertEqual(validator('1'), Decimal('1')) self.assertEqual(validator('1.2'), Decimal('1.2')) self.assertEqual(validator('-1.2'), Decimal('-1.2')) self.assertEqual(validator(Decimal('0')), Decimal('0')) self.assertEqual(validator(Decimal('-0')), Decimal('0')) self.assertEqual(validator(Decimal('-0.0000001')), Decimal('0')) self.assertEqual(validator(Decimal('-0.000001')), Decimal('-0.000001')) self.assertEqual(validator(Decimal('0.1')), Decimal('0.1')) self.assertEqual(validator(Decimal('-1.2')), Decimal('-1.2')) with self.assertRaises(ValidationError) as ctx: validator('text') self.assertEqual(ctx.exception.message, 'Ensure delay is a number.')