def save_event(db: Connection, event: Event) -> None: with db: if event.unit.is_stored: db[ACTUAL_KEY][event.channel] = event.dict() if event.unit.is_logged: db[f'log:{event.channel}'][timestamp_key( event.timestamp)] = event.dict(include=EVENT_INCLUDE)
def get_log(db: Connection, channel: str, period: timedelta) -> List[Event]: """ Gets the channel log within the specified period until now. """ return [ Event(**event) for event in db[f'log:{channel}'][timestamp_key(datetime.now() - period):] ]
async def events(self): for i in count(start=1): logger.trace('Sleeping for {interval} seconds…', interval=self.interval) await sleep(self.interval) yield Event(channel=f'clock:{self.sub_channel}', value=i, title=self.title, unit=Unit.TEXT)
def yield_events(self, feed: Any) -> Iterable[Event]: if feed['actual']['sunrise']: sunrise = parse_datetime(feed['actual']['sunrise']) yield Event( channel='buienradar:sunrise', value=sunrise, unit=Unit.DATETIME, title='Sunrise', ) else: logger.warning('Sunrise time is missing.') sunrise = None if feed['actual']['sunset']: sunset = parse_datetime(feed['actual']['sunset']) yield Event( channel='buienradar:sunset', value=sunset, unit=Unit.DATETIME, title='Sunset', ) else: logger.warning('Sunset time is missing.') sunset = None if sunset and sunrise: yield Event( channel='buienradar:day_length', value=(sunset - sunrise), unit=Unit.TIMEDELTA, title='Day Length', ) try: measurement = self.find_measurement(feed) except KeyError as e: logger.error('Station ID {} is not found.', e) return timestamp = parse_datetime(measurement['timestamp']) for key, channel, unit, title in channels: yield Event( channel=f'buienradar:{self.station_id}:{channel}', value=measurement[key], unit=unit, timestamp=timestamp, title=f'{measurement["stationname"]} {title}', )
def yield_devices_events(devices: dict, prefix: str, keys: List[Tuple[str, Unit, str]]) -> Iterable[Event]: for id_, device in devices.items(): for key, unit, title in keys: yield Event( channel=f'{prefix}:{id_}:{key}', value=device[key], unit=unit, title=f'{device.get("name_long") or device["name"]} {title}', )
async def events(self): try: yield Event( channel=f'file:{self.sub_channel}', value=self.preprocess_value(self.path.read_text()), unit=self.unit, title=self.title, ) except IOError as e: logger.error('I/O error in {channel}:', channel=self) logger.error('{e}', e=e) logger.debug('Next reading in {interval} seconds.', interval=self.interval) await sleep(self.interval)
async def on_startup(app: Application): """ Set up the web application. """ context: Context = app['context'] await context.on_event( Event( value=pkg_resources.get_distribution('my_iot').version, channel='my_iot:version', unit=Unit.TEXT, title='My IoT version', )) # noinspection PyAsyncCall create_task(context.run_services())
async def on_event(self, event: Event): """ Handle the single event. """ logger.info('{key} = {value!r}', key=event.channel, value=event.value) previous = self.db[ACTUAL_KEY].get(event.channel) await run_in_executor(save_event, self.db, event) previous = Event(**previous) if previous is not None else None # noinspection PyAsyncCall create_task( router.on_event( event=event, previous=previous, actual=(await run_in_executor(get_actual, self.db)), session=self.session, ))
def yield_events(event: MessageEvent) -> Iterable[Event]: data: dict = loads(event.data)['data'] devices: dict = data['devices'] yield from yield_devices_events(data['structures'], 'nest:structure', [ ('away', Unit.ENUM, 'Away'), ('wwn_security_state', Unit.ENUM, 'Security State'), ]) yield from yield_devices_events(devices['cameras'], 'nest:camera', [ ('is_streaming', Unit.BOOLEAN, 'Streaming'), ('is_online', Unit.BOOLEAN, 'Online'), ('snapshot_url', Unit.IMAGE_URL, 'Snapshot'), ]) yield from yield_devices_events( devices['thermostats'], 'nest:thermostat', [ ('ambient_temperature_c', Unit.CELSIUS, 'Ambient Temperature'), ('humidity', Unit.RH, 'Humidity'), ('is_online', Unit.BOOLEAN, 'Online'), ('hvac_state', Unit.ENUM, 'HVAC'), ('target_temperature_c', Unit.CELSIUS, 'Target Temperature'), ]) yield from yield_devices_events(devices['smoke_co_alarms'], 'nest:smoke_co_alarm', [ ('is_online', Unit.BOOLEAN, 'Online'), ]) for camera_id, camera in devices['cameras'].items(): last_event = camera.get('last_event') if last_event: yield Event( channel=f'nest:camera:{camera_id}:last_animated_image_url', value=last_event['animated_image_url'], unit=Unit.IMAGE_URL, timestamp=datetime.strptime(last_event['start_time'], timestamp_format), title=f'{camera["name_long"]} Last Event', )
async def get_channel(request: web.Request) -> dict: context: Context = request.app['context'] channel: str = request.match_info['channel'] try: raw_event: Dict[Any, Any] = context.db[ACTUAL_KEY][channel] except KeyError: raise HTTPNotFound(text='Channel is not found.') event = Event(**raw_event) try: period = timedelta(seconds=abs(int(request.query.get('period')))) except (TypeError, ValueError): period = DEFAULT_PERIOD events = await run_in_executor(get_log, context.db, channel, period) chart = None if events: if event.unit.is_float: chart = await run_in_executor(make_float_chart, events) return { 'chart': chart, 'event': event, 'has_events': bool(events), 'raw_event': raw_event, 'request': request, }
def get_actual(db: Connection) -> Mapping[str, Event]: """ Get actual channel values. """ return {key: Event(**value) for key, value in db[ACTUAL_KEY].items()}