diff --git a/doc/software_installation.md b/doc/software_installation.md index 264d8f95..4facafba 100644 --- a/doc/software_installation.md +++ b/doc/software_installation.md @@ -86,7 +86,7 @@ $ cd pizero_bikecomputer Assume Serial interface is on and login shell is off in raspi-config and GPS device is connected as /dev/ttyS0. If GPS device is /dev/ttyAMA0, modify gpsd config file(/etc/default/gpsd). ``` -$ sudo apt-get install gpsd gpsd-clients python3-dateutil +$ sudo apt-get install gpsd gpsd-clients $ sudo pip3 install gps3 timezonefinder $ sudo cp install/etc/default/gpsd /etc/default/gpsd $ sudo systemctl enable gpsd @@ -99,7 +99,6 @@ Check with `cgps` or `gpsmon` command. Assume I2C interface is on in raspi-config. ``` -$ sudo apt-get install python3-dateutil $ sudo pip3 install timezonefinder pa1010d ``` diff --git a/modules/button_config.py b/modules/button_config.py index 353cace9..0d274e0b 100644 --- a/modules/button_config.py +++ b/modules/button_config.py @@ -146,7 +146,7 @@ class Button_Config: G_BUTTON_MODE_IS_CHANGE = False G_BUTTON_MODE_PAGES = { "MAIN": ["MAIN", "MAIN_1"], - #'MAP': ['MAP','MAP_1','MAP_2'], + # 'MAP': ['MAP','MAP_1','MAP_2'], "MAP": ["MAP", "MAP_1"], "COURSE_PROFILE": ["COURSE_PROFILE", "COURSE_PROFILE_1"], } diff --git a/modules/config.py b/modules/config.py index 6d25b2c6..efd0d034 100644 --- a/modules/config.py +++ b/modules/config.py @@ -430,8 +430,6 @@ class Config: G_GPS_NULLVALUE = "n/a" # GPS speed cutoff (the distance in 1 seconds at 0.36km/h is 10cm) G_GPS_SPEED_CUTOFF = G_AUTOSTOP_CUTOFF # m/s - # timezone (not use, get from GPS position) - G_TIMEZONE = None # GPSd error handling G_GPSD_PARAM = { "EPX_EPY_CUTOFF": 100.0, @@ -1072,7 +1070,7 @@ def hardware_wifi_bt(self, status): "sed", "-i", "-e", - 's/^DEVICES\="\/dev\/ttyS0"/\#DEVICES\="\/dev\/ttyS0"/', + r's/^DEVICES\="\/dev\/ttyS0"/\#DEVICES\="\/dev\/ttyS0"/', "/etc/default/gpsd", ], False, @@ -1083,7 +1081,7 @@ def hardware_wifi_bt(self, status): "sed", "-i", "-e", - 's/^\#DEVICES\="\/dev\/ttyAMA0"/DEVICES\="\/dev\/ttyAMA0"/', + r's/^\#DEVICES\="\/dev\/ttyAMA0"/DEVICES\="\/dev\/ttyAMA0"/', "/etc/default/gpsd", ], False, diff --git a/modules/helper/ble_gatt_server.py b/modules/helper/ble_gatt_server.py index f160a613..20e3b2aa 100644 --- a/modules/helper/ble_gatt_server.py +++ b/modules/helper/ble_gatt_server.py @@ -23,6 +23,7 @@ NMEA_MODE_3D, NMEA_MODE_NO_FIX, ) +from modules.utils.time import set_time from logger import app_logger # Message first and last byte markers @@ -43,16 +44,8 @@ class GadgetbridgeService(Service): status = False gps_status = False - # TODO this has become useless. AFAIU it's preventing to handle more than once the setTime message during the \ - # lifetime of the service, with current changes it time would be set each time the message is received - timestamp_done = False - message = None - # TODO, - # if we want to be precise we should account the time of sending/receiving message for the setTime command - # it is sent through 8 messages (should still be less than 1s) - time_correction = 0 # seconds timediff_from_utc = timedelta(hours=0) def __init__(self, product, sensor, gui): @@ -97,7 +90,9 @@ def rx_characteristic(self, value, options): self.message = None async def on_off_uart_service(self): - if self.status: + self.status = not self.status + + if not self.status: self.bus.disconnect() else: self.bus = await get_message_bus() @@ -108,14 +103,17 @@ async def on_off_uart_service(self): advert = Advertisement(self.product, [self.service_uuid], 0, 60) await advert.register(self.bus, adapter) - self.status = not self.status + return self.status def on_off_gadgetbridge_gps(self): - if not self.gps_status: + self.gps_status = not self.gps_status + + if self.gps_status: self.send_message('{t:"gps_power", status:true}') else: self.send_message('{t:"gps_power", status:false}') - self.gps_status = not self.gps_status + + return self.gps_status @staticmethod def decode_b64(match_object): @@ -129,13 +127,18 @@ def decode_message(self, message: str): if res is not None: time_diff = timedelta(hours=float(res.group(2))) - utctime = ( - datetime.fromtimestamp(int(res.group(1))) - - time_diff - + timedelta(seconds=self.time_correction) - ).replace(tzinfo=timezone.utc) self.timediff_from_utc = time_diff - self.sensor.get_utc_time(utctime) + # we have a known time fix, we can use it to set the time of the system before we get gps fix + utctime = ( + ( + datetime.fromtimestamp(int(res.group(1))) + - time_diff + # we could also account for the time of message reception + ) + .replace(tzinfo=timezone.utc) + .isoformat() + ) + set_time(utctime) elif message.startswith("GB("): message = message.lstrip("GB(").rstrip(")") diff --git a/modules/logger/logger_fit.py b/modules/logger/logger_fit.py index 0b0113fb..65b67612 100644 --- a/modules/logger/logger_fit.py +++ b/modules/logger/logger_fit.py @@ -556,7 +556,8 @@ def get_summary(self, message_num, local_message_num, lap_num, cur): if message_num == 18: lap_fields.append(5) lap_data.append(2) - app_logger.debug(lap_fields, lap_data) + app_logger.debug(lap_fields) + app_logger.debug(lap_data) l_num = self.get_local_message_num(message_num, lap_fields) if l_num == -1: # write header if needed diff --git a/modules/pyqt/menu/pyqt_system_menu_widget.py b/modules/pyqt/menu/pyqt_system_menu_widget.py index 15a3ad17..62fa6314 100644 --- a/modules/pyqt/menu/pyqt_system_menu_widget.py +++ b/modules/pyqt/menu/pyqt_system_menu_widget.py @@ -57,8 +57,8 @@ def setup_menu(self): ("Bluetooth", "toggle", wifi_bt_button_func_bt), ("BT Tethering", "submenu", self.bt_tething), ("IP Address", "dialog", self.show_ip_address), - ("Gadgetbridge", "toggle", lambda: self.onoff_ble_uart_service(True)), - ("Get Location", "toggle", lambda: self.onoff_gadgetbridge_gps(True)), + ("Gadgetbridge", "toggle", self.onoff_ble_uart_service), + ("Get Location", "toggle", self.onoff_gadgetbridge_gps), ) self.add_buttons(button_conf) @@ -77,8 +77,6 @@ def preprocess(self): if self.config.G_IS_RASPI: self.onoff_wifi_bt(change=False, key="Wifi") self.onoff_wifi_bt(change=False, key="Bluetooth") - self.onoff_ble_uart_service(change=False) - self.onoff_gadgetbridge_gps(change=False) def onoff_wifi_bt(self, change=True, key=None): if change: @@ -96,20 +94,18 @@ def show_ip_address(self): self.config.gui.show_dialog_ok_only(None, address) @qasync.asyncSlot() - async def onoff_ble_uart_service(self, change=True): - if change: - await self.config.ble_uart.on_off_uart_service() - self.buttons["Gadgetbridge"].change_toggle(self.config.ble_uart.status) - self.buttons["Get Location"].onoff_button(self.config.ble_uart.status) + async def onoff_ble_uart_service(self): + status = await self.config.ble_uart.on_off_uart_service() + self.buttons["Gadgetbridge"].change_toggle(status) + self.buttons["Get Location"].onoff_button(status) - def onoff_gadgetbridge_gps(self, change=True): - if change: - self.config.ble_uart.on_off_gadgetbridge_gps() - self.buttons["Get Location"].change_toggle(self.config.ble_uart.gps_status) + def onoff_gadgetbridge_gps(self): + status = self.config.ble_uart.on_off_gadgetbridge_gps() + self.buttons["Get Location"].change_toggle(status) class DebugMenuWidget(MenuWidget): - is_log_lebel_debug = False + is_log_level_debug = False def setup_menu(self): button_conf = ( @@ -160,11 +156,11 @@ def set_log_level_to_debug(self, change=True): if change: if app_logger.level == logging.DEBUG: app_logger.setLevel(level=logging.INFO) - self.is_log_lebel_debug = False + self.is_log_level_debug = False else: app_logger.setLevel(level=logging.DEBUG) - self.is_log_lebel_debug = True - self.buttons["Debug Level Log"].change_toggle(self.is_log_lebel_debug) + self.is_log_level_debug = True + self.buttons["Debug Level Log"].change_toggle(self.is_log_level_debug) class BluetoothTetheringListWidget(ListWidget): diff --git a/modules/sensor/gps/adafruit_uart.py b/modules/sensor/gps/adafruit_uart.py index 9b51823f..84fd1fe3 100644 --- a/modules/sensor/gps/adafruit_uart.py +++ b/modules/sensor/gps/adafruit_uart.py @@ -1,5 +1,4 @@ import asyncio -import time from logger import app_logger from .base import AbstractSensorGPS diff --git a/modules/sensor/gps/base.py b/modules/sensor/gps/base.py index 936c73da..0d06b98d 100644 --- a/modules/sensor/gps/base.py +++ b/modules/sensor/gps/base.py @@ -1,16 +1,12 @@ import abc import asyncio -import re -from datetime import datetime, time, timedelta +from datetime import datetime, time import numpy as np -from dateutil import parser, tz -from timezonefinder import TimezoneFinder from modules.sensor.sensor import Sensor -from modules.utils.cmd import exec_cmd, exec_cmd_return_value from modules.utils.geo import get_dist_on_earth, get_track_str -from logger import app_logger +from modules.utils.time import set_time, set_timezone USED_SAT_CUTOFF = 3 HDOP_CUTOFF_MODERATE = 10.0 @@ -232,7 +228,7 @@ def id_or_none(value): # timezone if not self.is_fixed and valid_pos and mode == NMEA_MODE_3D: - self.is_fixed = self.set_timezone(lat, lon) + self.is_fixed = set_timezone(lat, lon) # modify altitude with course if ( @@ -299,59 +295,4 @@ def get_utc_time(self, gps_time): return if not self.is_time_modified: - self.is_time_modified = self.set_time(gps_time) - - @staticmethod - def set_time(gps_time): - app_logger.info(f"try to modify time by gps to {gps_time}") - - # TODO, we probably only get iso format now so this could be replaced by fromisoformat - # (and we can drop the requirement on dateutil) - l_time = parser.parse(gps_time) - - # kernel version date - kernel_date = datetime(2019, 1, 1, 0, 0, 0, 0, tz.tzutc()) - kernel_date_str = exec_cmd_return_value(["uname", "-v"], cmd_print=False) - - # "#1253 Thu Aug 15 11:37:30 BST 2019" - if len(kernel_date_str) >= 34: - m = re.search(r"^.+(\w{3}) (\d+).+(\d{4})$", kernel_date_str) - - if m: - time_str = f"{m.group(3)} {m.group(1)} {m.group(2)} 00:00:00 UTC" - kernel_date = parser.parse(time_str) - - if l_time < kernel_date: - return False - - exec_cmd( - ["sudo", "date", "-u", "--set", l_time.strftime("%Y/%m/%d %H:%M:%S")], - cmd_print=False, - ) - return True - - def set_timezone(self, lat, lon): - app_logger.info("try to modify timezone by gps...") - - tz_finder = TimezoneFinder() - - try: - tz_str = tz_finder.timezone_at(lng=lon, lat=lat) - - if tz_str is None: - # certain_timezone_at is deprecated since timezonefinder 6.2.0 - tz_str = tz_finder.certain_timezone_at(lng=lon, lat=lat) - - if tz_str is not None: - ret_code = exec_cmd( - ["sudo", "timedatectl", "set-timezone", tz_str], cmd_print=False - ) - if not ret_code: # 0 = success - self.config.G_TIMEZONE = tz_str - return True - except TypeError as e: - app_logger.exception(f"Incorrect lat, lon passed: {e}") - return False - except Exception as e: - app_logger.warning(f"Could not set timezone: {e}") - return False + self.is_time_modified = set_time(gps_time) diff --git a/modules/utils/time.py b/modules/utils/time.py new file mode 100644 index 00000000..9e7e494b --- /dev/null +++ b/modules/utils/time.py @@ -0,0 +1,56 @@ +from datetime import datetime + +from timezonefinder import TimezoneFinder + +from modules.utils.cmd import exec_cmd, exec_cmd_return_value +from logger import app_logger + + +def set_time(time_info): + app_logger.info(f"try to modify time to {time_info}") + + last_known_date = exec_cmd_return_value( + [ + "git", + "log", + "-1", + "--format=%cI", + "--date=iso-strict", + ], + cmd_print=False, + ) + + if datetime.fromisoformat(time_info) < datetime.fromisoformat(last_known_date): + return False + + exec_cmd( + ["sudo", "date", "-u", "--set", time_info], + cmd_print=False, + ) + return True + + +def set_timezone(lat, lon): + app_logger.info("try to modify timezone by gps...") + + tz_finder = TimezoneFinder() + try: + tz_str = tz_finder.timezone_at(lng=lon, lat=lat) + + if tz_str is None: + # certain_timezone_at is deprecated since timezonefinder 6.2.0 + tz_str = tz_finder.certain_timezone_at(lng=lon, lat=lat) + + if tz_str is not None: + ret_code = exec_cmd( + ["sudo", "timedatectl", "set-timezone", tz_str], cmd_print=False + ) + if ret_code: # 0 = success + app_logger.warning(f"Timezone {tz_str} be could not set: {ret_code}") + return True + except TypeError as e: + app_logger.exception(f"Incorrect lat, lon passed: {e}") + return False + except Exception as e: + app_logger.warning(f"Could not set timezone: {e}") + return False diff --git a/reqs/min.in b/reqs/min.in index d23212c2..d434313b 100644 --- a/reqs/min.in +++ b/reqs/min.in @@ -4,7 +4,6 @@ git+https://github.com/hishizuka/crdp.git numpy==1.25.2 oyaml==1.0 pillow===10.0.0 -python-dateutil==2.8.2 pyqtgraph==0.13.3 qasync==0.24.0 timezonefinder==6.2.0 \ No newline at end of file diff --git a/reqs/min.txt b/reqs/min.txt index 81a89063..12c7aaa0 100644 --- a/reqs/min.txt +++ b/reqs/min.txt @@ -18,7 +18,6 @@ numpy==1.25.2 oyaml==1.0 pillow===10.0.0 pyqtgraph==0.13.3 -python-dateutil==2.8.2 pyyaml==6.0.1 qasync==0.24.0 six==1.16.0