def received_message(self, message): if not hasattr(self, 'metadata'): return allowed_types = [ Event.Types.OUTPUT_CHANGE, Event.Types.THERMOSTAT_CHANGE, Event.Types.THERMOSTAT_GROUP_CHANGE, Event.Types.SHUTTER_CHANGE, Event.Types.INPUT_CHANGE ] try: data = msgpack.loads(message.data) event = Event.deserialize(data) if event.type == Event.Types.ACTION: if event.data['action'] == 'set_subscription': subscribed_types = [ stype for stype in event.data['types'] if stype in allowed_types ] cherrypy.engine.publish( 'update-events-receiver', self.metadata['client_id'], {'subscribed_types': subscribed_types}) elif event.type == Event.Types.PING: self.send(msgpack.dumps( Event(event_type=Event.Types.PONG, data=None).serialize()), binary=True) except Exception as ex: logger.exception('Error receiving message: %s', ex)
def v0_event_thermostat_changed(self, thermostat_number, active_preset, current_setpoint, actual_temperature, percentages, room): """ :type thermostat_number: int :type active_preset: str :type current_setpoint: float :type actual_temperature: float :type percentages: list :type room: int """ logger.debug( 'v0_event_thermostat_changed: {}'.format(thermostat_number)) self._message_client.send_event(OMBusEvents.THERMOSTAT_CHANGE, {'id': thermostat_number}) location = {'room_id': room} for callback in self._event_subscriptions: callback( Event(event_type=Event.Types.THERMOSTAT_CHANGE, data={ 'id': thermostat_number, 'status': { 'preset': active_preset, 'current_setpoint': current_setpoint, 'actual_temperature': actual_temperature, 'output_0': percentages[0], 'output_1': percentages[1] }, 'location': location }))
def test_events_sent_to_cloud(self): container = {} def _send_events(events): container['events'] = events cloud = CloudAPIClient('test.example.com') cloud.send_events = _send_events event_sender = EventSender(cloud) # Don't start, trigger manually self.assertEqual(len(event_sender._queue), 0) self.assertFalse(event_sender._batch_send_events()) event_sender.enqueue_event(Event(Event.Types.OUTPUT_CHANGE, None)) event_sender.enqueue_event(Event(Event.Types.THERMOSTAT_CHANGE, None)) event_sender.enqueue_event(Event(Event.Types.INPUT_TRIGGER, None)) self.assertEqual(len(event_sender._queue), 2) self.assertTrue(event_sender._batch_send_events()) self.assertEqual(len(event_sender._queue), 0) self.assertEqual(len(container.get('events', [])), 2)
def _thermostat_group_changed(self, status): self._message_client.send_event(OMBusEvents.THERMOSTAT_CHANGE, {'id': None}) for callback in self._event_subscriptions: callback( Event(event_type=Event.Types.THERMOSTAT_GROUP_CHANGE, data={ 'id': 0, 'status': { 'state': status['state'], 'mode': status['mode'] }, 'location': {} }))
def _thermostat_changed(self, thermostat_id, status): """ Executed by the Thermostat Status tracker when an output changed state """ self._message_client.send_event(OMBusEvents.THERMOSTAT_CHANGE, {'id': thermostat_id}) location = {'room_id': self._thermostats_config[thermostat_id]['room']} for callback in self._event_subscriptions: callback( Event(event_type=Event.Types.THERMOSTAT_CHANGE, data={ 'id': thermostat_id, 'status': { 'preset': status['preset'], 'current_setpoint': status['current_setpoint'], 'actual_temperature': status['actual_temperature'], 'output_0': status['output_0'], 'output_1': status['output_1'] }, 'location': location }))
def _handle_input_status(self, event_json): event = Event.deserialize(event_json) # get relevant event details input_id = event.data['id'] status = event.data['status'] for receiver in self._input_status_receivers: version = receiver.input_status.get('version', 1) if version == 1: # Backwards compatibility: only send rising edges of the input (no input releases) if status: IO._with_catch('input status', receiver, [(input_id, None)]) elif version == 2: # Version 2 will send ALL input status changes AND in a dict format data = {'input_id': input_id, 'status': status} IO._with_catch('input status', receiver, [data]) else: error = NotImplementedError( 'Version {} is not supported for input status decorators'. format(version)) IO._log_exception('input status', error)
def v0_event_thermostat_group_changed(self, thermostat_group): """ :type thermostat_group: models.ThermostatGroup """ logger.debug( 'v0_event_thermostat_group_changed: {}'.format(thermostat_group)) self._message_client.send_event(OMBusEvents.THERMOSTAT_CHANGE, {'id': None}) for callback in self._event_subscriptions: callback( Event(event_type=Event.Types.THERMOSTAT_GROUP_CHANGE, data={ 'id': 0, 'status': { 'state': 'ON' if thermostat_group.on else 'OFF', 'mode': 'COOLING' if thermostat_group.mode == 'cooling' else 'HEATING' }, 'location': {} }))
def test_get_special_methods(self): """ Test getting special methods on a plugin. """ controller = None try: PluginControllerTest._create_plugin( 'P1', """ import time from plugins.base import * class P1(OMPluginBase): name = 'P1' version = '0.1.0' interfaces = [('webui', '1.0')] def __init__(self, webservice, logger): OMPluginBase.__init__(self, webservice, logger) self._bg_running = False self._input_data = None self._input_data_version_2 = None self._output_data = None self._event_data = None @om_expose(auth=True) def html_index(self): return 'HTML' @om_expose(auth=False) def get_log(self): return {'bg_running': self._bg_running, 'input_data': self._input_data, 'input_data_version_2': self._input_data_version_2, 'output_data': self._output_data, 'event_data': self._event_data} @input_status def input(self, input_status_inst): self._input_data = input_status_inst @input_status(version=2) def input_version_2(self, input_status_inst): self._input_data_version_2 = input_status_inst @input_status(version=3) def input_version_3(self, input_status_inst): self._input_data_version_3 = input_status_inst @output_status def output(self, output_status_inst): self._output_data = output_status_inst @receive_events def recv_events(self, code): self._event_data = code @background_task def run(self): while True: self._bg_running = True time.sleep(1) """) observer = type('Observer', (), {})() observer.get_outputs = lambda: [{ 'id': 1, 'dimmer': 5, 'status': 1 }] controller = PluginControllerTest._get_controller( observer=observer) controller.start() response = controller._request('P1', 'html_index') self.assertEqual(response, 'HTML') rising_input_event = { 'id': 1, 'status': True, 'location': { 'room_id': 1 } } controller.process_observer_event( Event(event_type=Event.Types.INPUT_CHANGE, data=rising_input_event)) falling_input_event = { 'id': 2, 'status': False, 'location': { 'room_id': 5 } } controller.process_observer_event( Event(event_type=Event.Types.INPUT_CHANGE, data=falling_input_event)) output_event = { 'id': 1, 'status': { 'on': True, 'value': 5 }, 'location': { 'room_id': 5 } } controller.process_observer_event( Event(event_type=Event.Types.OUTPUT_CHANGE, data=output_event)) controller.process_event(1) keys = [ 'input_data', 'input_data_version_2', 'output_data', 'event_data' ] start = time.time() while time.time() - start < 2: response = controller._request('P1', 'get_log') if all(response[key] is not None for key in keys): break time.sleep(0.1) self.assertEqual( response, { 'bg_running': True, 'input_data': [1, None ], # only rising edges should be triggered 'input_data_version_2': { 'input_id': 2, 'status': False }, 'output_data': [[1, 5]], 'event_data': 1 }) plugin_logs = controller.get_logs().get('P1', '') self.assertTrue( 'Version 3 is not supported for input status decorators' in plugin_logs) finally: if controller is not None: controller.stop() PluginControllerTest._destroy_plugin('P1')