Skip to content

Commit

Permalink
Improve error handling
Browse files Browse the repository at this point in the history
Improve error handling.
  • Loading branch information
tmjo committed Oct 23, 2021
1 parent 1b91abd commit c1e23d8
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 25 deletions.
53 changes: 36 additions & 17 deletions custom_components/norwegiantide/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
DEFAULT_TIME_ZONE: dt.tzinfo = pytz.timezone("Europe/Oslo")
TIMEOUT = 30 # seconds
API_ATTRIBUTION = "Data from ©Kartverket (www.kartverket.no)"
API_ATTRIBUTION_URL = "http://sehavniva.no/"
API_NAME = "norwegiantide"
VERSION = "2021.3.5"
API_USER_AGENT = f"{API_NAME}/{VERSION} https://github.com/tmjo/ha-norwegiantide"
Expand Down Expand Up @@ -93,8 +94,11 @@ async def async_get_data(self) -> dict:
self.location = self.process_location()
self.tidedatatime = self.process_tidedatatime()
self.highlow = self.process_high_low()
except AttributeError as e:
_LOGGER.error("Unable to decode API response.")
# except AttributeError as e:
except:
_LOGGER.error(
f"Unable to read API response - service may be down (try {API_ATTRIBUTION_URL})."
)
return self.process_data()

async def get_xml_data(self):
Expand All @@ -112,9 +116,10 @@ async def get_xml_data(self):
response = await self.api_wrapper("get", self.get_url(datatype="tab"))
content = await response.text()
self.highlowdata = self.xml_high_low(content)
except AttributeError as exception:
# except AttributeError as e:
except Exception as e:
_LOGGER.debug(
f"Unable to decode xml possibly due to previous error getting data. {exception}"
f"Unable to decode xml possibly due to previous error getting data. {e}"
)

def process_data(self):
Expand All @@ -139,7 +144,9 @@ def process_data(self):
API_LON: self.getLocation(API_LON),
"location_details": self.getLocationDetails(),
"next_tide": self.next_tide,
"next_tide_time": {self.next_tide.get("time", None)},
"next_tide_time": {
None if self.next_tide is None else self.next_tide.get("time", None)
},
"next_tide_low": self.next_tide_low,
"next_tide_high": self.next_tide_high,
"time_to_next_tide": self.time_to_next_tide,
Expand Down Expand Up @@ -307,7 +314,7 @@ def getData(self, tidedatatime=None, type=API_FORECAST):
return datalist

def getDataAll(self, tidedatatime=None):
"""Get list of data [datestamp, data]. """
"""Get list of data [datestamp, data]."""
if tidedatatime is None:
tidedatatime = self.tidedatatime

Expand Down Expand Up @@ -350,8 +357,13 @@ def getTimeToNextTide(self, nexttide=None, highlow=None):
nexttide = self.next_tide
elif highlow is not None:
nexttide = self.getNextTide(highlow)
return nexttide.get("time") - dt_now()
except TypeError:

if nexttide is not None:
return nexttide.get("time") - dt_now()
else:
return None
# except TypeError:
except:
return None

def getTideState(self, nexttide=None):
Expand Down Expand Up @@ -380,15 +392,18 @@ def getTideState(self, nexttide=None):
elif nexttide.get("flag") == API_HIGH:
return f"{API_LOW}"
return "Normal"
except TypeError:
# except TypeError:
except:
return None

def getTideStateEbbFlow(self, nexttide=None):
"""Get direction of tide (ebb/flow)."""
if nexttide is None:
nexttide = self.getNextTide()

if nexttide.get("flag") == API_LOW:
if nexttide is None:
tidestate = None
elif nexttide.get("flag") == API_LOW:
tidestate = API_EBB # if next tide is low, then it is ebbing
elif nexttide.get("flag") == API_HIGH:
tidestate = API_FLOW # if next tide is high, then it is flowing
Expand Down Expand Up @@ -420,19 +435,22 @@ def getLastData(self, type=None):

def getCurrentData(self, type=None):
"""Get current data i.e. data nearest to actual time."""
nearest = self.getNearestData(self.tidedatatime, dt_now())
_LOGGER.debug(f"getCurrentData: {nearest} - {self.tidedatatime[nearest]}")
return self.tidedatatime[nearest]
try:
nearest = self.getNearestData(self.tidedatatime, dt_now())
_LOGGER.debug(f"getCurrentData: {nearest} - {self.tidedatatime[nearest]}")
return self.tidedatatime[nearest]
except:
return None

def getCurrentDataObservation(self):
"""Get current observation i.e. observation nearest to actual time."""
lastobservation = self.getLastData(type=API_OBSERVATION).get(
API_OBSERVATION, None
)
_LOGGER.debug(
f"Last observation: {lastobservation} with time {lastobservation.get('time')}"
)
if lastobservation is not None:
_LOGGER.debug(
f"Last observation: {lastobservation} with time {lastobservation.get('time')}"
)
time = lastobservation.get("time", None)
return self.tidedatatime.get(dt_parse_datetime(time), None)
else:
Expand All @@ -442,7 +460,8 @@ def getNearestData(self, items, data):
"""Return the datetime in items which is the closest to the data pivot, datetypes must support comparison and subtraction."""
try:
return min(items, key=lambda x: abs(x - data))
except TypeError:
# except TypeError:
except:
return None

def plot_tidedata(
Expand Down
28 changes: 20 additions & 8 deletions custom_components/norwegiantide/entity.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,10 +116,10 @@ def unit_of_measurement(self):
"""Return the unit of measurement of this entity, if any."""
return self._units

# @property
# def available(self):
# """Return True if entity is available."""
# return self._state is not None
@property
def available(self):
"""Return True if entity is available."""
return self._state is not None

@property
def state_attributes(self):
Expand Down Expand Up @@ -170,12 +170,12 @@ def get_value_from_key(self, key):
if isinstance(data, dict) and second is not None:
value = data.get(second, None)
if value is None:
_LOGGER.error(f"Did not find data for {first}.{second}")
_LOGGER.debug(f"Did not find data for {first}.{second}")
elif data is not None:
value = data
else:
value = None
_LOGGER.error(f"Did not find data for {first}")
_LOGGER.debug(f"Did not find data for {first}")

if type(value) is datetime:
value = dt.as_local(value)
Expand All @@ -191,6 +191,18 @@ async def async_update(self):

self._state = self.get_value_from_key(self._state_key)
if self._state_func is not None:
self._state = self._state_func(self.coordinator.data.get(self._state_key))
try:
self._state = self._state_func(
self.coordinator.data.get(self._state_key)
)
except Exception as e:
_LOGGER.debug(
f"Failed when trying state function {self._state_func}: {e}"
)
if self._convert_units_func is not None:
self._state = self._convert_units_func(self._state, self._units)
try:
self._state = self._convert_units_func(self._state, self._units)
except Exception as e:
_LOGGER.debug(
f"Failed when trying conversion {self._convert_units_func}: {e}"
)

0 comments on commit c1e23d8

Please sign in to comment.