diff --git a/rtc_service/README.md b/rtc_service/README.md index 43a19649..5a495fa1 100644 --- a/rtc_service/README.md +++ b/rtc_service/README.md @@ -15,6 +15,7 @@ The RTC service needs four parameters to start. | WM_RTC_TIMEZONE_OFFSET_S | Timezone offset in seconds of the local time. | It is taken in account only if WM_RTC_TIMEZONE_FROM_GATEWAY_CLOCK is False. | | WM_RTC_GET_TIME_FROM_LOCAL | Asserts if the rtc time is sent from local time or from a ntp server time | If set to True, it is assumed that gateways are synchronize. The default value is False | | WM_RTC_NTP_SERVER_ADDRESS | Address of the ntp server to query the time if it is taken from an ntp server. | WM_RTC_GET_TIME_FROM_LOCAL must be set to False for that option to be taken into account | +| WM_RTC_RETRY_PERIOD_S | Period in seconds of the retries sending the rtc time when it couldn't be sent to the network. | It might take additional 5 seconds to know that the rtc time can't be retrieved. | RTC service is available as a docker image to ease the integration. diff --git a/rtc_service/rtc_service.py b/rtc_service/rtc_service.py index d2ad818b..cc9abd7c 100644 --- a/rtc_service/rtc_service.py +++ b/rtc_service/rtc_service.py @@ -7,12 +7,14 @@ import logging import ntplib import os +import socket import struct import sys from time import sleep, time from threading import Thread from wirepas_gateway.dbus.dbus_client import BusClient +import wirepas_mesh_messaging as wmm PKG_NAME = "rtc_service" @@ -68,6 +70,7 @@ class SynchronizationThread(Thread): def __init__( self, period, + retry_period, timezone_offset_s, timezone_from_gateway_clock, get_time_from_local, @@ -79,6 +82,8 @@ def __init__( Args: period: The period to send gateway time to the network + retry_period: Period in seconds of the retries sending + the ntp rtc time when it couldn't be sent to the network. timezone_offset_s: Offset of the local time in seconds if timezone_from_gateway_clock is False. timezone_from_gateway_clock: True if timezone offset must be taken from gateway clock. @@ -98,6 +103,7 @@ def __init__( # How often to send time self.period = period + self.retry_period = retry_period self.timezone_from_gateway_clock = timezone_from_gateway_clock if timezone_from_gateway_clock is True: self.timezone_offset_s = datetime.datetime.now(datetime.timezone.utc).astimezone().utcoffset().seconds @@ -117,26 +123,36 @@ def __init__( self.sink_manager = sink_manager logging.info(f"Expected RTC sending period is set to {self.period}s") - def publish_time(self): + def publish_time(self) -> bool: """ Publish the rtc time in the network. + Return True if the time could published, return False otherwise. """ if not self.get_time_from_local: try: req = self.ntp_client.request(self.ntp_server_address, version=3) timestamp = req.dest_time + req.offset - except ntplib.NTPException as err: - logging.warning("Couldn't get time from NTP server. (%s)", err) - return + except (ntplib.NTPException, socket.gaierror) as err: + logging.warning("An error occured when trying to get time from NTP server. (%s)", err) + return False else: timestamp = time() timestamp_ms = int(timestamp*1000) data_payload = RTC_VERSION.to_bytes(2, "little") + encode_tlv(timestamp_ms, self.timezone_offset_s) + + sinks = self.sink_manager.get_sinks() + if not sinks: + logging.error("No sinks are detected!") + return False + logging.info("Send rtc message to the network") - for sink in self.sink_manager.get_sinks(): + logging.debug("Payload: %s", data_payload.hex()) + sent_to_one_sink: bool = False + + for sink in sinks: start = time() - sink.send_data( + res = sink.send_data( dst=BROADCAST_ADDRESS, src_ep=RTC_SOURCE_EP, dst_ep=RTC_DEST_EP, @@ -144,16 +160,24 @@ def publish_time(self): initial_time=0, data=data_payload ) - logging.debug("time elapsed to send RTC time through the gateway: " - f"{int((time()-start)*1000)}ms") + logging.debug("time elapsed to send RTC time through the gateway: %dms", + int((time() - start) * 1000)) + if res == wmm.GatewayResultCode.GW_RES_OK: + sent_to_one_sink = True + else: + logging.error("rtc time couldn't be sent to %s sink: %s", sink.sink_id, res) + + return sent_to_one_sink def run(self): """ Main loop that send periodically gateway time to the network. """ while True: - self.publish_time() - sleep(self.period) + if self.publish_time(): + sleep(self.period) + else: + sleep(self.retry_period) class RtcService(BusClient): @@ -167,6 +191,7 @@ def __init__(self, settings, **kwargs): super(RtcService, self).__init__(**kwargs) self.synchronization_thread = SynchronizationThread( settings.rtc_synchronization_period_s, + settings.rtc_retry_period_s, settings.timezone_offset_s, settings.timezone_from_gateway_clock, settings.get_time_from_local, @@ -214,6 +239,15 @@ def main(): help=("Period of time to send a new rtc time in the network."), ) + parser.add_argument( + "--rtc_retry_period_s", + default=os.environ.get("WM_RTC_RETRY_PERIOD_S", 1), + action="store", + type=str2int, + help=("Period in seconds of the retries sending the rtc time when it couldn't be sent to the network." + "Note: It might take additional 5 seconds to know that the rtc time can't be retrieved.") + ) + parser.add_argument( "--timezone_from_gateway_clock", default=os.environ.get("WM_RTC_TIMEZONE_FROM_GATEWAY_CLOCK", False),