Remove initialisation warning from the boiler
This commit is contained in:
1 parent
9a58cc5296
commit
d79bba15b0
2 files changed
+28
-3
No files matched your search
+11
-3
@@ -17,7 +17,9 @@ class BoilerWatchdog(hass.Hass, LoggerInterface):
|
|||||||
if self.AD.plugins.get_plugin_object(self.mqtt_namespace) is None:
|
if self.AD.plugins.get_plugin_object(self.mqtt_namespace) is None:
|
||||||
raise RuntimeError('MQTT plugin missing; configure it and restart AppDaemon')
|
raise RuntimeError('MQTT plugin missing; configure it and restart AppDaemon')
|
||||||
self.last_heartbeat = None
|
self.last_heartbeat = None
|
||||||
|
self.waiting_since = time.monotonic()
|
||||||
self.fault = False
|
self.fault = False
|
||||||
|
self.warned = False
|
||||||
self.listen_event(self._mqtt_event, 'MQTT_MESSAGE', namespace=self.mqtt_namespace)
|
self.listen_event(self._mqtt_event, 'MQTT_MESSAGE', namespace=self.mqtt_namespace)
|
||||||
self.run_every(self._check, 'now', 10)
|
self.run_every(self._check, 'now', 10)
|
||||||
self._check()
|
self._check()
|
||||||
@@ -25,18 +27,24 @@ class BoilerWatchdog(hass.Hass, LoggerInterface):
|
|||||||
def _mqtt_event(self, event, data, kwargs):
|
def _mqtt_event(self, event, data, kwargs):
|
||||||
if data.get('topic') == self.base + '/heartbeat':
|
if data.get('topic') == self.base + '/heartbeat':
|
||||||
self.last_heartbeat = time.monotonic()
|
self.last_heartbeat = time.monotonic()
|
||||||
if self.fault:
|
if self.warned:
|
||||||
self.log_info('Boiler climate heartbeat recovered')
|
self.log_info('Boiler climate heartbeat recovered')
|
||||||
self.fault = False
|
self.fault = False
|
||||||
|
self.warned = False
|
||||||
elif data.get('topic') is None and data.get('state') == 'Connected':
|
elif data.get('topic') is None and data.get('state') == 'Connected':
|
||||||
self.last_heartbeat = None
|
self.last_heartbeat = None
|
||||||
|
self.waiting_since = time.monotonic()
|
||||||
self.fault = False
|
self.fault = False
|
||||||
|
self.warned = False
|
||||||
self._check()
|
self._check()
|
||||||
|
|
||||||
def _check(self, kwargs=None):
|
def _check(self, kwargs=None):
|
||||||
if self.last_heartbeat is None or time.monotonic() - self.last_heartbeat >= self.timeout:
|
age = time.monotonic() - (self.waiting_since if self.last_heartbeat is None else self.last_heartbeat)
|
||||||
|
if self.last_heartbeat is None or age >= self.timeout:
|
||||||
if not self.fault:
|
if not self.fault:
|
||||||
self.call_service('mqtt/publish', namespace=self.mqtt_namespace,
|
self.call_service('mqtt/publish', namespace=self.mqtt_namespace,
|
||||||
topic=self.base + '/availability', payload='offline', qos=0, retain=True)
|
topic=self.base + '/availability', payload='offline', qos=0, retain=True)
|
||||||
self.log_warning('Boiler climate unavailable: waiting for a fresh heartbeat')
|
|
||||||
self.fault = True
|
self.fault = True
|
||||||
|
if age >= self.timeout and not self.warned:
|
||||||
|
self.log_warning('Boiler climate unavailable: no heartbeat within the timeout')
|
||||||
|
self.warned = True
|
||||||
@@ -467,16 +467,31 @@ class WatchdogTests(unittest.TestCase):
|
|||||||
a = object.__new__(BoilerWatchdog)
|
a = object.__new__(BoilerWatchdog)
|
||||||
a.base, a.mqtt_namespace, a.timeout = 'appdaemon/test', 'mqtt', 180
|
a.base, a.mqtt_namespace, a.timeout = 'appdaemon/test', 'mqtt', 180
|
||||||
a.last_heartbeat, a.fault = None, False
|
a.last_heartbeat, a.fault = None, False
|
||||||
|
a.waiting_since, a.warned = 1000, False
|
||||||
a.call_service, a.log = Mock(), Mock()
|
a.call_service, a.log = Mock(), Mock()
|
||||||
a.initialize_logger_interface(a, ascii_encode=False)
|
a.initialize_logger_interface(a, ascii_encode=False)
|
||||||
return a
|
return a
|
||||||
|
|
||||||
def test_missing_heartbeat_publishes_offline_once(self):
|
def test_missing_heartbeat_publishes_offline_once(self):
|
||||||
a = self.app()
|
a = self.app()
|
||||||
|
with patch('boilerwatchdog.time.monotonic', return_value=1000):
|
||||||
a._check()
|
a._check()
|
||||||
a._check()
|
a._check()
|
||||||
a.call_service.assert_called_once_with('mqtt/publish', namespace='mqtt',
|
a.call_service.assert_called_once_with('mqtt/publish', namespace='mqtt',
|
||||||
topic=a.base + '/availability', payload='offline', qos=0, retain=True)
|
topic=a.base + '/availability', payload='offline', qos=0, retain=True)
|
||||||
|
a.log.assert_not_called()
|
||||||
|
a._mqtt_event('', {'topic': a.base + '/heartbeat'}, {})
|
||||||
|
a.log.assert_not_called()
|
||||||
|
|
||||||
|
def test_first_heartbeat_missing_beyond_timeout_warns_once(self):
|
||||||
|
a = self.app()
|
||||||
|
with patch('boilerwatchdog.time.monotonic', return_value=1000):
|
||||||
|
a._check()
|
||||||
|
with patch('boilerwatchdog.time.monotonic', return_value=1180):
|
||||||
|
a._check()
|
||||||
|
a._check()
|
||||||
|
self.assertEqual(a.log.call_count, 1)
|
||||||
|
self.assertEqual(a.log.call_args.kwargs['level'], 'WARNING')
|
||||||
|
|
||||||
def test_timeout_and_recovery_do_not_override_sensor_availability(self):
|
def test_timeout_and_recovery_do_not_override_sensor_availability(self):
|
||||||
a = self.app()
|
a = self.app()
|
||||||
@@ -488,6 +503,7 @@ class WatchdogTests(unittest.TestCase):
|
|||||||
with patch('boilerwatchdog.time.monotonic', return_value=1180):
|
with patch('boilerwatchdog.time.monotonic', return_value=1180):
|
||||||
a._check()
|
a._check()
|
||||||
self.assertTrue(a.fault)
|
self.assertTrue(a.fault)
|
||||||
|
self.assertTrue(a.warned)
|
||||||
a.call_service.reset_mock()
|
a.call_service.reset_mock()
|
||||||
a._mqtt_event('', {'topic': a.base + '/heartbeat'}, {})
|
a._mqtt_event('', {'topic': a.base + '/heartbeat'}, {})
|
||||||
self.assertFalse(a.fault)
|
self.assertFalse(a.fault)
|
||||||
@@ -500,6 +516,7 @@ class WatchdogTests(unittest.TestCase):
|
|||||||
self.assertIsNone(a.last_heartbeat)
|
self.assertIsNone(a.last_heartbeat)
|
||||||
self.assertTrue(a.fault)
|
self.assertTrue(a.fault)
|
||||||
self.assertEqual(a.call_service.call_args.kwargs['payload'], 'offline')
|
self.assertEqual(a.call_service.call_args.kwargs['payload'], 'offline')
|
||||||
|
a.log.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
|||||||
Reference in new issue
Block a user