async def async_update(self): """Get the latest data and updates the states.""" # Get previous values of start and end p_start, p_end = self._period # Parse templates self.update_period() start, end = self._period # Convert times to UTC start = dt_util.as_utc(start) end = dt_util.as_utc(end) p_start = dt_util.as_utc(p_start) p_end = dt_util.as_utc(p_end) now = datetime.datetime.now() # Compute integer timestamps start_timestamp = math.floor(dt_util.as_timestamp(start)) end_timestamp = math.floor(dt_util.as_timestamp(end)) p_start_timestamp = math.floor(dt_util.as_timestamp(p_start)) p_end_timestamp = math.floor(dt_util.as_timestamp(p_end)) now_timestamp = math.floor(dt_util.as_timestamp(now)) # If period has not changed and current time after the period end... if (start_timestamp == p_start_timestamp and end_timestamp == p_end_timestamp and end_timestamp <= now_timestamp): # Don't compute anything as the value cannot have changed return await self.opp.async_add_executor_job(self._update, start, end, now_timestamp, start_timestamp, end_timestamp)
def test_as_timestamp(): """Test as_timestamp method.""" ts = 1462401234 utc_dt = dt_util.utc_from_timestamp(ts) assert ts == dt_util.as_timestamp(utc_dt) utc_iso = utc_dt.isoformat() assert ts == dt_util.as_timestamp(utc_iso) # confirm the ability to handle a string passed in delta = dt_util.as_timestamp("2016-01-01 12:12:12") delta -= dt_util.as_timestamp("2016-01-01 12:12:11") assert delta == 1
async def test_timezone_intervals(opp): """Test date sensor behavior in a timezone besides UTC.""" new_tz = dt_util.get_time_zone("America/New_York") assert new_tz is not None dt_util.set_default_time_zone(new_tz) device = time_date.TimeDateSensor(opp, "date") now = dt_util.utc_from_timestamp(50000) with patch("openpeerpower.util.dt.utcnow", return_value=now): next_time = device.get_next_interval() # start of local day in EST was 18000.0 # so the second day was 18000 + 86400 assert next_time.timestamp() == 104400 new_tz = dt_util.get_time_zone("America/Edmonton") assert new_tz is not None dt_util.set_default_time_zone(new_tz) now = dt_util.parse_datetime("2017-11-13 19:47:19-07:00") device = time_date.TimeDateSensor(opp, "date") with patch("openpeerpower.util.dt.utcnow", return_value=now): next_time = device.get_next_interval() assert next_time.timestamp() == dt_util.as_timestamp("2017-11-14 00:00:00-07:00") # Entering DST new_tz = dt_util.get_time_zone("Europe/Prague") assert new_tz is not None dt_util.set_default_time_zone(new_tz) now = dt_util.parse_datetime("2020-03-29 00:00+01:00") with patch("openpeerpower.util.dt.utcnow", return_value=now): next_time = device.get_next_interval() assert next_time.timestamp() == dt_util.as_timestamp("2020-03-30 00:00+02:00") now = dt_util.parse_datetime("2020-03-29 03:00+02:00") with patch("openpeerpower.util.dt.utcnow", return_value=now): next_time = device.get_next_interval() assert next_time.timestamp() == dt_util.as_timestamp("2020-03-30 00:00+02:00") # Leaving DST now = dt_util.parse_datetime("2020-10-25 00:00+02:00") with patch("openpeerpower.util.dt.utcnow", return_value=now): next_time = device.get_next_interval() assert next_time.timestamp() == dt_util.as_timestamp("2020-10-26 00:00:00+01:00") now = dt_util.parse_datetime("2020-10-25 23:59+01:00") with patch("openpeerpower.util.dt.utcnow", return_value=now): next_time = device.get_next_interval() assert next_time.timestamp() == dt_util.as_timestamp("2020-10-26 00:00:00+01:00")
async def test_connection_state_signalling(opp, aioclient_mock, mock_unifi_websocket): """Verify connection statesignalling and connection state are working.""" client = { "hostname": "client", "ip": "10.0.0.1", "is_wired": True, "last_seen": dt_util.as_timestamp(dt_util.utcnow()), "mac": "00:00:00:00:00:01", } await setup_unifi_integration(opp, aioclient_mock, clients_response=[client]) # Controller is connected assert opp.states.get("device_tracker.client").state == "home" mock_unifi_websocket(state=STATE_DISCONNECTED) await opp.async_block_till_done() # Controller is disconnected assert opp.states.get("device_tracker.client").state == "unavailable" mock_unifi_websocket(state=STATE_RUNNING) await opp.async_block_till_done() # Controller is once again connected assert opp.states.get("device_tracker.client").state == "home"
def convert_time_to_utc(timestr): """Take a string like 08:00:00 and convert it to a unix timestamp.""" combined = datetime.combine(dt_util.start_of_local_day(), dt_util.parse_time(timestr)) if combined < datetime.now(): combined = combined + timedelta(days=1) return dt_util.as_timestamp(combined)
async def test_timezone_intervals_empty_parameter(opp): """Test get_interval() without parameters.""" new_tz = dt_util.get_time_zone("America/Edmonton") assert new_tz is not None dt_util.set_default_time_zone(new_tz) device = time_date.TimeDateSensor(opp, "date") next_time = device.get_next_interval() assert next_time.timestamp() == dt_util.as_timestamp("2017-11-14 00:00:00-07:00")
def get_next_interval(self): """Compute next time an update should occur.""" now = dt_util.utcnow() if self.type == "date": tomorrow = dt_util.as_local(now) + timedelta(days=1) return dt_util.start_of_local_day(tomorrow) if self.type == "beat": # Add 1 hour because @0 beats is at 23:00:00 UTC. timestamp = dt_util.as_timestamp(now + timedelta(hours=1)) interval = 86.4 else: timestamp = dt_util.as_timestamp(now) interval = 60 delta = interval - (timestamp % interval) next_interval = now + timedelta(seconds=delta) _LOGGER.debug("%s + %s -> %s (%s)", now, delta, next_interval, self.type) return next_interval
def get_next_interval(self, now=None): """Compute next time an update should occur.""" if now is None: now = dt_util.utcnow() if self.type == "date": now = dt_util.start_of_local_day(dt_util.as_local(now)) return now + timedelta(seconds=86400) if self.type == "beat": interval = 86.4 else: interval = 60 timestamp = int(dt_util.as_timestamp(now)) delta = interval - (timestamp % interval) return now + timedelta(seconds=delta)
def update(self): """Get the latest data and updates the states.""" mydata = self.opp.data[DATA_HYDRAWISE].data _LOGGER.debug("Updating Hydrawise sensor: %s", self._name) relay_data = mydata.relays[self.data["relay"] - 1] if self._sensor_type == "watering_time": if relay_data["timestr"] == "Now": self._state = int(relay_data["run"] / 60) else: self._state = 0 else: # _sensor_type == 'next_cycle' next_cycle = min(relay_data["time"], TWO_YEAR_SECONDS) _LOGGER.debug("New cycle time: %s", next_cycle) self._state = dt.utc_from_timestamp( dt.as_timestamp(dt.now()) + next_cycle).isoformat()
def __init__(self, opp, name): """Initialize Demo mailbox.""" super().__init__(opp, name) self._messages = {} txt = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. " for idx in range(0, 10): msgtime = int(dt.as_timestamp(dt.utcnow()) - 3600 * 24 * (10 - idx)) msgtxt = f"Message {idx + 1}. {txt * (1 + idx * (idx % 2))}" msgsha = sha1(msgtxt.encode("utf-8")).hexdigest() msg = { "info": { "origtime": msgtime, "callerid": "John Doe <212-555-1212>", "duration": "10", }, "text": msgtxt, "sha": msgsha, } self._messages[msgsha] = msg
async def async_added_to_opp(self): """Subscribe to updates.""" if KEY_RAIN_DELAY in self._controller.init_data: self._state = self._controller.init_data[ KEY_RAIN_DELAY] / 1000 > as_timestamp(now()) # If the controller was in a rain delay state during a reboot, this re-sets the timer if self._state is True: delay_end = utc_from_timestamp( self._controller.init_data[KEY_RAIN_DELAY] / 1000) _LOGGER.debug("Re-setting rain delay timer for %s", delay_end) self._cancel_update = async_track_point_in_utc_time( self.opp, self._delay_expiration, delay_end) self.async_on_remove( async_dispatcher_connect( self.opp, SIGNAL_RACHIO_RAIN_DELAY_UPDATE, self._async_handle_any_update, ))
def forgiving_as_timestamp(value): """Try to convert value to timestamp.""" try: return dt_util.as_timestamp(value) except (ValueError, TypeError): return None
def get(self, request): """Get SpaceAPI data.""" opp = request.app["opp"] spaceapi = dict(opp.data[DATA_SPACEAPI]) is_sensors = spaceapi.get("sensors") location = {ATTR_LAT: opp.config.latitude, ATTR_LON: opp.config.longitude} try: location[ATTR_ADDRESS] = spaceapi[ATTR_LOCATION][CONF_ADDRESS] except KeyError: pass except TypeError: pass state_entity = spaceapi["state"][ATTR_ENTITY_ID] space_state = opp.states.get(state_entity) if space_state is not None: state = { ATTR_OPEN: space_state.state != "off", ATTR_LASTCHANGE: dt_util.as_timestamp(space_state.last_updated), } else: state = {ATTR_OPEN: "null", ATTR_LASTCHANGE: 0} with suppress(KeyError): state[ATTR_ICON] = { ATTR_OPEN: spaceapi["state"][CONF_ICON_OPEN], ATTR_CLOSE: spaceapi["state"][CONF_ICON_CLOSED], } data = { ATTR_API: SPACEAPI_VERSION, ATTR_CONTACT: spaceapi[CONF_CONTACT], ATTR_ISSUE_REPORT_CHANNELS: spaceapi[CONF_ISSUE_REPORT_CHANNELS], ATTR_LOCATION: location, ATTR_LOGO: spaceapi[CONF_LOGO], ATTR_SPACE: spaceapi[CONF_SPACE], ATTR_STATE: state, ATTR_URL: spaceapi[CONF_URL], } with suppress(KeyError): data[ATTR_CAM] = spaceapi[CONF_CAM] with suppress(KeyError): data[ATTR_SPACEFED] = spaceapi[CONF_SPACEFED] with suppress(KeyError): data[ATTR_STREAM] = spaceapi[CONF_STREAM] with suppress(KeyError): data[ATTR_FEEDS] = spaceapi[CONF_FEEDS] with suppress(KeyError): data[ATTR_CACHE] = spaceapi[CONF_CACHE] with suppress(KeyError): data[ATTR_PROJECTS] = spaceapi[CONF_PROJECTS] with suppress(KeyError): data[ATTR_RADIO_SHOW] = spaceapi[CONF_RADIO_SHOW] if is_sensors is not None: sensors = {} for sensor_type in is_sensors: sensors[sensor_type] = [] for sensor in spaceapi["sensors"][sensor_type]: sensor_data = self.get_sensor_data(opp, spaceapi, sensor) sensors[sensor_type].append(sensor_data) data[ATTR_SENSORS] = sensors return self.json(data)
def update(self): """Get the latest data and updates the states.""" # Get previous values of start and end p_start, p_end = self._period # Parse templates self.update_period() start, end = self._period # Convert times to UTC start = dt_util.as_utc(start) end = dt_util.as_utc(end) p_start = dt_util.as_utc(p_start) p_end = dt_util.as_utc(p_end) now = datetime.datetime.now() # Compute integer timestamps start_timestamp = math.floor(dt_util.as_timestamp(start)) end_timestamp = math.floor(dt_util.as_timestamp(end)) p_start_timestamp = math.floor(dt_util.as_timestamp(p_start)) p_end_timestamp = math.floor(dt_util.as_timestamp(p_end)) now_timestamp = math.floor(dt_util.as_timestamp(now)) # If period has not changed and current time after the period end... if (start_timestamp == p_start_timestamp and end_timestamp == p_end_timestamp and end_timestamp <= now_timestamp): # Don't compute anything as the value cannot have changed return # Get history between start and end history_list = history.state_changes_during_period( self.opptart, end, str(self._entity_id)) if self._entity_id not in history_list.keys(): return # Get the first state last_state = history.get_state(self.opptart, self._entity_id) last_state = last_state is not None and last_state == self._entity_state last_time = start_timestamp elapsed = 0 count = 0 # Make calculations for item in history_list.get(self._entity_id): current_state = item.state == self._entity_state current_time = item.last_changed.timestamp() if last_state: elapsed += current_time - last_time if current_state and not last_state: count += 1 last_state = current_state last_time = current_time # Count time elapsed between last history state and end of measure if last_state: measure_end = min(end_timestamp, now_timestamp) elapsed += measure_end - last_time # Save value in hours self.value = elapsed / 3600 # Save counter self.count = count
async def test_option_ignore_wired_bug(opp, aioclient_mock, mock_unifi_websocket): """Test option to ignore wired bug.""" client = { "ap_mac": "00:00:00:00:02:01", "essid": "ssid", "hostname": "client", "ip": "10.0.0.1", "is_wired": False, "last_seen": dt_util.as_timestamp(dt_util.utcnow()), "mac": "00:00:00:00:00:01", } config_entry = await setup_unifi_integration( opp, aioclient_mock, options={CONF_IGNORE_WIRED_BUG: True}, clients_response=[client], ) controller = opp.data[UNIFI_DOMAIN][config_entry.entry_id] assert len(opp.states.async_entity_ids(TRACKER_DOMAIN)) == 1 # Client is wireless client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_HOME assert client_state.attributes["is_wired"] is False # Trigger wired bug client["is_wired"] = True mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) await opp.async_block_till_done() # Wired bug in effect client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_HOME assert client_state.attributes["is_wired"] is True # pass time new_time = dt_util.utcnow() + controller.option_detection_time with patch("openpeerpower.util.dt.utcnow", return_value=new_time): async_fire_time_changed(opp, new_time) await opp.async_block_till_done() # Timer marks client as away client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_NOT_HOME assert client_state.attributes["is_wired"] is True # Mark client as connected again mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) await opp.async_block_till_done() # Ignoring wired bug allows client to go home again even while affected client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_HOME assert client_state.attributes["is_wired"] is True # Make client wireless client["is_wired"] = False mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) await opp.async_block_till_done() # Client is wireless and still connected client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_HOME assert client_state.attributes["is_wired"] is False
async def test_wireless_client_go_wired_issue(opp, aioclient_mock, mock_unifi_websocket): """Test the solution to catch wireless device go wired UniFi issue. UniFi has a known issue that when a wireless device goes away it sometimes gets marked as wired. """ client = { "essid": "ssid", "hostname": "client", "ip": "10.0.0.1", "is_wired": False, "last_seen": dt_util.as_timestamp(dt_util.utcnow()), "mac": "00:00:00:00:00:01", } config_entry = await setup_unifi_integration(opp, aioclient_mock, clients_response=[client]) controller = opp.data[UNIFI_DOMAIN][config_entry.entry_id] assert len(opp.states.async_entity_ids(TRACKER_DOMAIN)) == 1 # Client is wireless client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_HOME assert client_state.attributes["is_wired"] is False # Trigger wired bug client["is_wired"] = True mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) await opp.async_block_till_done() # Wired bug fix keeps client marked as wireless client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_HOME assert client_state.attributes["is_wired"] is False # Pass time new_time = dt_util.utcnow() + controller.option_detection_time with patch("openpeerpower.util.dt.utcnow", return_value=new_time): async_fire_time_changed(opp, new_time) await opp.async_block_till_done() # Marked as home according to the timer client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_NOT_HOME assert client_state.attributes["is_wired"] is False # Try to mark client as connected mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) await opp.async_block_till_done() # Make sure it don't go online again until wired bug disappears client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_NOT_HOME assert client_state.attributes["is_wired"] is False # Make client wireless client["is_wired"] = False mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) await opp.async_block_till_done() # Client is no longer affected by wired bug and can be marked online client_state = opp.states.get("device_tracker.client") assert client_state.state == STATE_HOME assert client_state.attributes["is_wired"] is False
async def test_option_ssid_filter(opp, aioclient_mock, mock_unifi_websocket): """Test the SSID filter works. Client will travel from a supported SSID to an unsupported ssid. Client on SSID2 will be removed on change of options. """ client = { "essid": "ssid", "hostname": "client", "is_wired": False, "last_seen": dt_util.as_timestamp(dt_util.utcnow()), "mac": "00:00:00:00:00:01", } client_on_ssid2 = { "essid": "ssid2", "hostname": "client_on_ssid2", "is_wired": False, "last_seen": 1562600145, "mac": "00:00:00:00:00:02", } config_entry = await setup_unifi_integration( opp, aioclient_mock, clients_response=[client, client_on_ssid2]) controller = opp.data[UNIFI_DOMAIN][config_entry.entry_id] assert len(opp.states.async_entity_ids(TRACKER_DOMAIN)) == 2 assert opp.states.get("device_tracker.client").state == STATE_HOME assert opp.states.get( "device_tracker.client_on_ssid2").state == STATE_NOT_HOME # Setting SSID filter will remove clients outside of filter opp.config_entries.async_update_entry( config_entry, options={CONF_SSID_FILTER: ["ssid"]}, ) await opp.async_block_till_done() # Not affected by SSID filter assert opp.states.get("device_tracker.client").state == STATE_HOME # Removed due to SSID filter assert not opp.states.get("device_tracker.client_on_ssid2") # Roams to SSID outside of filter client["essid"] = "other_ssid" mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) # Data update while SSID filter is in effect shouldn't create the client client_on_ssid2["last_seen"] = dt_util.as_timestamp(dt_util.utcnow()) mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client_on_ssid2], }) await opp.async_block_till_done() # SSID filter marks client as away assert opp.states.get("device_tracker.client").state == STATE_NOT_HOME # SSID still outside of filter assert not opp.states.get("device_tracker.client_on_ssid2") # Remove SSID filter opp.config_entries.async_update_entry( config_entry, options={CONF_SSID_FILTER: []}, ) await opp.async_block_till_done() mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client], }) mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client_on_ssid2], }) await opp.async_block_till_done() assert opp.states.get("device_tracker.client").state == STATE_HOME assert opp.states.get("device_tracker.client_on_ssid2").state == STATE_HOME # Time pass to mark client as away new_time = dt_util.utcnow() + controller.option_detection_time with patch("openpeerpower.util.dt.utcnow", return_value=new_time): async_fire_time_changed(opp, new_time) await opp.async_block_till_done() assert opp.states.get("device_tracker.client").state == STATE_NOT_HOME mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client_on_ssid2], }) await opp.async_block_till_done() # Client won't go away until after next update assert opp.states.get("device_tracker.client_on_ssid2").state == STATE_HOME # Trigger update to get client marked as away mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client_on_ssid2], }) await opp.async_block_till_done() new_time = (dt_util.utcnow() + controller.option_detection_time + timedelta(seconds=1)) with patch("openpeerpower.util.dt.utcnow", return_value=new_time): async_fire_time_changed(opp, new_time) await opp.async_block_till_done() assert opp.states.get( "device_tracker.client_on_ssid2").state == STATE_NOT_HOME
async def test_tracked_clients(opp, aioclient_mock, mock_unifi_websocket): """Test the update_items function with some clients.""" client_1 = { "ap_mac": "00:00:00:00:02:01", "essid": "ssid", "hostname": "client_1", "ip": "10.0.0.1", "is_wired": False, "last_seen": 1562600145, "mac": "00:00:00:00:00:01", } client_2 = { "ip": "10.0.0.2", "is_wired": True, "last_seen": 1562600145, "mac": "00:00:00:00:00:02", "name": "Client 2", } client_3 = { "essid": "ssid2", "hostname": "client_3", "ip": "10.0.0.3", "is_wired": False, "last_seen": 1562600145, "mac": "00:00:00:00:00:03", } client_4 = { "essid": "ssid", "hostname": "client_4", "ip": "10.0.0.4", "is_wired": True, "last_seen": dt_util.as_timestamp(dt_util.utcnow()), "mac": "00:00:00:00:00:04", } client_5 = { "essid": "ssid", "hostname": "client_5", "ip": "10.0.0.5", "is_wired": True, "last_seen": None, "mac": "00:00:00:00:00:05", } await setup_unifi_integration( opp, aioclient_mock, options={CONF_SSID_FILTER: ["ssid"]}, clients_response=[client_1, client_2, client_3, client_4, client_5], known_wireless_clients=(client_4["mac"], ), ) assert len(opp.states.async_entity_ids(TRACKER_DOMAIN)) == 4 assert opp.states.get("device_tracker.client_1").state == STATE_NOT_HOME assert opp.states.get("device_tracker.client_2").state == STATE_NOT_HOME # Client on SSID not in SSID filter assert not opp.states.get("device_tracker.client_3") # Wireless client with wired bug, if bug active on restart mark device away assert opp.states.get("device_tracker.client_4").state == STATE_NOT_HOME # A client that has never been seen should be marked away. assert opp.states.get("device_tracker.client_5").state == STATE_NOT_HOME # State change signalling works mock_unifi_websocket(data={ "meta": { "message": MESSAGE_CLIENT }, "data": [client_1], }) await opp.async_block_till_done() assert opp.states.get("device_tracker.client_1").state == STATE_HOME