diff -Nru satellite-gtk-0.3.1/bin/satellite satellite-gtk-0.4.2/bin/satellite
--- satellite-gtk-0.3.1/bin/satellite 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/bin/satellite 2023-09-23 11:31:05.000000000 +0000
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
import os
diff -Nru satellite-gtk-0.3.1/data/appdata.xml satellite-gtk-0.4.2/data/appdata.xml
--- satellite-gtk-0.3.1/data/appdata.xml 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/data/appdata.xml 2023-09-23 11:31:05.000000000 +0000
@@ -1,5 +1,5 @@
-
+
page.codeberg.tpikonen.satellite
@@ -9,10 +9,11 @@
Check your GPS reception and save your tracks
Satellite displays global navigation satellite system (GNSS: that's GPS,
- Galileo, Glonass etc.) data obtained from the ModemManager API. You can use
- it to check the navigation satellite signal strength in your location and
- see your speed, coordinates and other parameters once a fix is obtained.
- It can also save GPX-tracks of your travels.
+ Galileo, Glonass etc.) data obtained from an NMEA source in your device.
+ Currently the ModemManager and gnss-share APIs are supported. You can use
+ it to check the navigation satellite signal strength and see your speed,
+ coordinates and other parameters once a fix is obtained. It can also save
+ GPX-tracks of your travels.
page.codeberg.tpikonen.satellite.desktop
https://codeberg.org/tpikonen/satellite
@@ -48,6 +49,35 @@
+
+
+ The geoidal release
+
+ - Add 'Geoidal separation' field to dataframe
+ - Display DOPs (PDOP, HDOP, VDOP) on a single dataframe line
+ - Various small fixes to gnss-share source, logging, NMEA parsing etc.
+
+
+
+
+
+ The automatic release
+
+ - Autodetect sources and source quirks when --source option is not given
+ - Some small fixes to mm_glib_source, NMEA parsing, flatpak, etc.
+
+
+
+
+
+ The managerial release
+
+ - Use mm-glib to talk to ModemManager, remove pydbus
+ - Support 'quirks' in the ModemManager source, e.g. Quectel talker fixes
+ - Various reliability fixes
+
+
+
The quickfix release
diff -Nru satellite-gtk-0.3.1/debian/changelog satellite-gtk-0.4.2/debian/changelog
--- satellite-gtk-0.3.1/debian/changelog 2023-01-22 15:06:59.000000000 +0000
+++ satellite-gtk-0.4.2/debian/changelog 2023-10-04 10:24:35.000000000 +0000
@@ -1,3 +1,12 @@
+satellite-gtk (0.4.2-1) unstable; urgency=medium
+
+ * Team upload
+
+ * New upstream release
+ * d/control: drop now-unneeded pydbus dependency
+
+ -- Arnaud Ferraris Wed, 04 Oct 2023 12:24:35 +0200
+
satellite-gtk (0.3.1-1) unstable; urgency=medium
* New upstream release
diff -Nru satellite-gtk-0.3.1/debian/control satellite-gtk-0.4.2/debian/control
--- satellite-gtk-0.3.1/debian/control 2023-01-22 14:57:33.000000000 +0000
+++ satellite-gtk-0.4.2/debian/control 2023-10-04 10:24:35.000000000 +0000
@@ -23,7 +23,6 @@
python3-gi,
python3-gpxpy,
python3-nmea2,
- python3-pydbus,
${misc:Depends},
${python3:Depends},
Description: Adaptive GTK application which displays GNSS data
diff -Nru satellite-gtk-0.3.1/.editorconfig satellite-gtk-0.4.2/.editorconfig
--- satellite-gtk-0.3.1/.editorconfig 1970-01-01 00:00:00.000000000 +0000
+++ satellite-gtk-0.4.2/.editorconfig 2023-09-23 11:31:05.000000000 +0000
@@ -0,0 +1,26 @@
+# EditorConfig is awesome: http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Unix-style newlines with a newline ending every file
+[*]
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
+charset = utf-8
+
+# 4 space indentation
+[*.{py,java,r,R}]
+indent_style = space
+indent_size = 4
+
+# 2 space indentation
+[*.{js,json,y{a,}ml,html,cwl}]
+indent_style = space
+indent_size = 2
+
+[*.{md,Rmd,rst}]
+trim_trailing_whitespace = false
+indent_style = space
+indent_size = 2
diff -Nru satellite-gtk-0.3.1/flatpak/page.codeberg.tpikonen.satellite.json satellite-gtk-0.4.2/flatpak/page.codeberg.tpikonen.satellite.json
--- satellite-gtk-0.3.1/flatpak/page.codeberg.tpikonen.satellite.json 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/flatpak/page.codeberg.tpikonen.satellite.json 1970-01-01 00:00:00.000000000 +0000
@@ -1,39 +0,0 @@
-{
- "app-id": "page.codeberg.tpikonen.satellite",
- "runtime": "org.gnome.Platform",
- "runtime-version": "43",
- "sdk": "org.gnome.Sdk",
- "command": "satellite",
- "rename-desktop-file": "satellite.desktop",
- "finish-args": [
- "--socket=fallback-x11",
- "--socket=wayland",
- "--share=ipc",
- "--device=dri",
- "--talk-name=org.gtk.vfs.*",
- "--system-talk-name=org.freedesktop.ModemManager1.*",
- "--filesystem=xdg-documents/satellite-tracks:create"
- ],
- "cleanup": [
- ],
- "modules": [
- "python3-requirements.json",
- {
- "name": "satellite",
- "sources": [
- {
- "type": "git",
- "path": "../",
- "branch": "main"
- }
- ],
- "buildsystem": "simple",
- "build-commands": [
- "pip3 install --verbose --no-index --no-deps --no-build-isolation --prefix=${FLATPAK_DEST} ./"
- ],
- "post-install": [
- "install -Dm644 data/appdata.xml $FLATPAK_DEST/share/metainfo/$FLATPAK_ID.appdata.xml"
- ]
- }
- ]
-}
diff -Nru satellite-gtk-0.3.1/flatpak/page.codeberg.tpikonen.satellite.yaml satellite-gtk-0.4.2/flatpak/page.codeberg.tpikonen.satellite.yaml
--- satellite-gtk-0.3.1/flatpak/page.codeberg.tpikonen.satellite.yaml 1970-01-01 00:00:00.000000000 +0000
+++ satellite-gtk-0.4.2/flatpak/page.codeberg.tpikonen.satellite.yaml 2023-09-23 11:31:05.000000000 +0000
@@ -0,0 +1,42 @@
+app-id: page.codeberg.tpikonen.satellite
+runtime: org.gnome.Platform
+runtime-version: "45"
+sdk: org.gnome.Sdk
+command: satellite
+rename-desktop-file: satellite.desktop
+finish-args:
+ - --socket=fallback-x11
+ - --socket=wayland
+ - --share=ipc
+ - --device=dri
+ - --talk-name=org.gtk.vfs.*
+ - --system-talk-name=org.freedesktop.ModemManager1.*
+ - --filesystem=xdg-documents/satellite-tracks:create
+ - --filesystem=/run/gnss-share.sock:ro
+cleanup: []
+modules:
+ - python3-requirements.json
+ - name: ModemManager
+ config-opts:
+ - --without-udev
+ - --with-udev-base-dir=/app/lib/udev
+ - --with-systemdsystemunitdir=/app/lib/systemd/system
+ - --without-examples
+ - --without-tests
+ - --without-mbim
+ - --without-qmi
+ - --without-qrtr
+ - --without-man
+ sources:
+ - type: archive
+ url: https://gitlab.freedesktop.org/mobile-broadband/ModemManager/-/archive/1.20.6/ModemManager-1.20.6.tar.gz
+ sha256: d3e8112810e48ba32e80757fced218cf65b135b5a2987dad6b431d8cfbba765f
+ - name: satellite
+ sources:
+ - type: git
+ path: ../
+ branch: main
+ buildsystem: simple
+ build-commands:
+ - pip3 install --verbose --no-index --no-deps --no-build-isolation --prefix=${FLATPAK_DEST} ./
+ - install -Dm644 data/appdata.xml $FLATPAK_DEST/share/metainfo/$FLATPAK_ID.appdata.xml
diff -Nru satellite-gtk-0.3.1/flatpak/python3-requirements.json satellite-gtk-0.4.2/flatpak/python3-requirements.json
--- satellite-gtk-0.3.1/flatpak/python3-requirements.json 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/flatpak/python3-requirements.json 2023-09-23 11:31:05.000000000 +0000
@@ -26,22 +26,8 @@
"sources": [
{
"type": "file",
- "url": "https://files.pythonhosted.org/packages/c9/13/6117f735c3e8083bfce0ccd31a1d561fc2adb0e0e2d1ab3ace12256a3513/pynmea2-1.18.0-py3-none-any.whl",
- "sha256": "098f9ffd89c4a6c5e137b8b59e5b38194888d4a557c50b003ebcf2c3c15ec22e"
- }
- ]
- },
- {
- "name": "python3-pydbus",
- "buildsystem": "simple",
- "build-commands": [
- "pip3 install --verbose --exists-action=i --no-index --find-links=\"file://${PWD}\" --prefix=${FLATPAK_DEST} \"pydbus\" --no-build-isolation"
- ],
- "sources": [
- {
- "type": "file",
- "url": "https://files.pythonhosted.org/packages/92/56/27148014c2f85ce70332f18612f921f682395c7d4e91ec103783be4fce00/pydbus-0.6.0-py2.py3-none-any.whl",
- "sha256": "66b80106352a718d80d6c681dc2a82588048e30b75aab933e4020eb0660bf85e"
+ "url": "https://files.pythonhosted.org/packages/75/24/1f575eb17a8135e54b3c243ff87e2f4d6b2389942836021d0628ed837559/pynmea2-1.19.0-py3-none-any.whl",
+ "sha256": "5138558b4fb5daa587b2c17de99eb43df0297039de1c98010c996624abfb00eb"
}
]
}
diff -Nru satellite-gtk-0.3.1/README.md satellite-gtk-0.4.2/README.md
--- satellite-gtk-0.3.1/README.md 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/README.md 2023-09-23 11:31:05.000000000 +0000
@@ -5,7 +5,7 @@
![Expanded satellite SNR view](https://github.com/flathub/page.codeberg.tpikonen.satellite/raw/master/screenshot-snr.png)
![Speedometer and track recording](https://github.com/flathub/page.codeberg.tpikonen.satellite/raw/master/screenshot-track.png)
-Satellite is an adaptive GTK / libhandy application which displays global navigation satellite system
+Satellite is an adaptive GTK3 / libhandy application which displays global navigation satellite system
(GNSS: GPS et al.) data obtained from [ModemManager](https://www.freedesktop.org/wiki/Software/ModemManager/)
or [gnss-share](https://gitlab.com/postmarketOS/gnss-share). It can also save your position to a GPX-file.
@@ -15,7 +15,7 @@
## Dependencies:
- python 3.6+, gi, Gtk, libhandy, pydbus, pynmea2, gpxpy
+ python 3.6+, gi, Gtk3, libhandy, libmm-glib, pynmea2, gpxpy
## Installing and running
@@ -45,9 +45,9 @@
Run
- pip3 install --user ./
+ pip install --user ./
-in the source tree root.
+in the source tree root (use `pipx` instead of `pip` if necessary).
This creates an executable Python script in `$HOME/.local/bin/satellite`.
@@ -55,7 +55,7 @@
Run
- flatpak-builder --install --user build-dir flatpak/page.codeberg.tpikonen.satellite.json
+ flatpak-builder --install --user build-dir flatpak/page.codeberg.tpikonen.satellite.yaml
in the source tree root to install a local build to the user flatpak repo.
diff -Nru satellite-gtk-0.3.1/requirements.txt satellite-gtk-0.4.2/requirements.txt
--- satellite-gtk-0.3.1/requirements.txt 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/requirements.txt 2023-09-23 11:31:05.000000000 +0000
@@ -1,3 +1,2 @@
gpxpy
pynmea2
-pydbus
diff -Nru satellite-gtk-0.3.1/satellite/application.py satellite-gtk-0.4.2/satellite/application.py
--- satellite-gtk-0.3.1/satellite/application.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/application.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,9 +1,8 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
import argparse
-import gi
-import gpxpy
+import importlib.resources as resources
import os
import re
import signal
@@ -12,26 +11,28 @@
import tokenize
from datetime import datetime
-import importlib.resources as resources
+import gi
+import gpxpy
import satellite.nmea as nmea
import satellite.quectel as quectel
+from satellite import __version__
+
+from .mm_glib_source import ModemManagerGLibNmeaSource
from .nmeasource import (
- ModemNoNMEAError,
- ModemLockedError,
+ GnssShareNmeaSource,
ModemError,
+ ModemLockedError,
+ ModemNoNMEAError,
NmeaSourceNotFoundError,
- QuectelNmeaSource,
- GnssShareNmeaSource,
)
from .util import bearing_to_arrow, have_touchscreen, now, unique_filename
-from .widgets import text_barchart, DataFrame
-from satellite import __version__
+from .widgets import DataFrame, text_barchart
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
gi.require_version('Handy', '1')
-from gi.repository import Gdk, Gio, GLib, Gtk, Handy # noqa: E402
+from gi.repository import GLib, Gdk, Gio, Gtk, Handy # noqa: E402, I100
appname = 'Satellite'
app_id = 'page.codeberg.tpikonen.satellite'
@@ -46,17 +47,21 @@
Handy.init()
desc = "Displays navigation satellite data and saves GPX tracks"
- parser = argparse.ArgumentParser(description=desc)
+ parser = argparse.ArgumentParser(
+ description=desc, formatter_class=argparse.RawTextHelpFormatter)
parser.add_argument(
'-c', '--console-output', dest='console_output',
action='store_true', default=False,
help='Output satellite data to console')
parser.add_argument(
'-s', '--source', dest='source',
- default='quectel',
- help='Select NMEA source. Options are '
- '\'quectel\' (default) for Quectel Modems or '
- '\'gnss-share\' when using gnss-share')
+ choices=['auto', 'quectel', 'mm', 'gnss-share'],
+ default='auto',
+ help="Select NMEA source. Options are:\n"
+ "'auto' (default) Automatic source detection\n"
+ "'quectel' ModemManager with Quectel quirks\n"
+ "'mm' ModemManager without quirks\n"
+ "'gnss-share' Read from gnss-share socket\n")
self.args = parser.parse_args()
GLib.unix_signal_add(GLib.PRIORITY_DEFAULT, signal.SIGINT,
@@ -90,7 +95,7 @@
self.source = None
- self.infolabel.set_markup("" + "\n"*10 + "")
+ self.infolabel.set_markup("" + "\n" * 10 + "")
self.dataframe = DataFrame()
# self.dataframe.header.set_text("Satellite info")
@@ -117,7 +122,7 @@
self.last_data = None
self.last_speed = None
self.last_update = None
- self.source_lost = False
+ self.had_error = False
self.sigint_received = False
self.refresh_rate = 1 # Really delay between updates in seconds
@@ -161,8 +166,6 @@
def on_startup(self, app):
self.create_actions()
- # Initialize modem after GUI startup
- GLib.idle_add(self.init_source)
def on_activate(self, app):
self.setup_styles()
@@ -171,33 +174,56 @@
if have_touchscreen():
self.datascroll.connect('edge-overshot', self.on_edge_overshot)
+ self.log_msg(f"{appname} version {__version__} started")
+ # Initialize modem after GUI startup
+ GLib.timeout_add(1000, self.init_source, None)
+
def on_shutdown(self, app):
- """Called after main loop exits."""
print("Cleaning up...")
self.gpx_write()
if self.source is not None:
self.source.close()
print("...done.")
- def init_source(self):
- self.log_msg(f"{appname} version {__version__} started")
+ def init_source(self, unused):
source_init = False
- self.log_msg(f'Trying to initialize source "{self.args.source}"')
-
- if self.args.source == 'quectel':
- source_init = self.init_quectel_source()
- elif self.args.source == 'gnss-share':
- source_init = self.init_gnss_share_source()
-
- if not source_init:
- self.log_msg('No NmeaSource initialized')
- return False # Remove from idle_add
+ if self.args.source == 'auto':
+ self.log_msg("Detecting NMEA sources...")
+ if not source_init:
+ source_init = self.init_gnss_share_source(autodetect=True)
+ if not source_init:
+ source_init = self.init_mm_source(
+ quirks=['detect'], autodetect=True)
+ if not source_init:
+ self.log_msg('NMEA source not found')
+ dialog = Gtk.MessageDialog(
+ parent=self.window, modal=True,
+ message_type=Gtk.MessageType.ERROR,
+ buttons=Gtk.ButtonsType.OK,
+ text="Could not find an NMEA source")
+ dialog.set_title("Error initializing NMEA source")
+ dialog.run()
+ dialog.destroy()
+ return GLib.SOURCE_REMOVE
+ else:
+ self.log_msg(f'NMEA source "{self.args.source}" selected')
+ if self.args.source == 'quectel':
+ source_init = self.init_mm_source(quirks=['QuectelTalker'])
+ elif self.args.source == 'mm':
+ source_init = self.init_mm_source()
+ elif self.args.source == 'gnss-share':
+ source_init = self.init_gnss_share_source()
+ if not source_init:
+ self.log_msg('Could not initialize NMEA source')
+ return GLib.SOURCE_REMOVE
self.log_msg(
- f"Source is {self.source.manufacturer}, model {self.source.model}"
- + f", revision {self.source.revision}"
- if self.source.revision else "")
+ f"Source is {self.source.manufacturer}"
+ + (f", model {self.source.model}" if self.source.model else "")
+ + (f", revision {self.source.revision}" if self.source.revision else "")
+ + (f" using {', '.join(self.source.quirks)} quirks"
+ if hasattr(self.source, "quirks") and self.source.quirks else ""))
if (self.source.model and self.source.model.startswith("QUECTEL")):
constellations = quectel.get_constellations(self.source)
@@ -218,14 +244,15 @@
return GLib.SOURCE_REMOVE
- def init_gnss_share_source(self):
+ def init_gnss_share_source(self, autodetect=False):
try:
self.source = GnssShareNmeaSource(self.location_update_cb)
self.source.initialize()
except Exception as e:
- fatal = False
+ if autodetect:
+ return False
self.log_msg(str(e))
- dtext = 'Can you access "/var/run/gnss-share.sock"?\n' + str(e)
+ dtext = str(e)
dialog = Gtk.MessageDialog(
parent=self.window, modal=True,
message_type=Gtk.MessageType.ERROR,
@@ -233,44 +260,40 @@
dialog.set_title("Error initializing NMEA source")
dialog.run()
dialog.destroy()
- if fatal:
- self.quit()
return False
return True
- def init_quectel_source(self):
+ def init_mm_source(self, quirks=[], autodetect=False):
try:
- self.source = QuectelNmeaSource(
+ self.source = ModemManagerGLibNmeaSource(
self.location_update_cb,
refresh_rate=self.refresh_rate,
+ quirks=quirks,
# save_filename=unique_filename(self.gpx_save_dir + '/nmeas',
# '.txt')
)
self.source.initialize()
except Exception as e:
- fatal = False
+ if autodetect:
+ return False
if isinstance(e, ModemLockedError):
self.log_msg("Modem is locked")
dtext = "Please unlock the Modem"
else:
- fatal = isinstance(e, gi.repository.GLib.GError)
- self.log_msg("Error initializing NMEA source")
etext = str(e)
+ self.log_msg(f"Error initializing ModemManager NMEA source: {etext}")
dtext = etext if etext else (
- "Could not find or initialize NMEA source")
+ "Could not initialize ModemManager NMEA source")
dialog = Gtk.MessageDialog(
parent=self.window, modal=True,
message_type=Gtk.MessageType.ERROR,
- buttons=Gtk.ButtonsType.CLOSE if fatal else Gtk.ButtonsType.OK,
+ buttons=Gtk.ButtonsType.OK,
text=dtext)
dialog.set_title("Error initializing NMEA source")
dialog.run()
dialog.destroy()
- if fatal:
- self.quit()
- return
return False
@@ -301,7 +324,7 @@
version=__version__,
comments="A program for showing navigation satellite data",
license_type=Gtk.License.GPL_3_0_ONLY,
- copyright="Copyright 2021-2022 Teemu Ikonen",
+ copyright="Copyright 2021-2023 Teemu Ikonen",
)
adlg.present()
@@ -407,6 +430,12 @@
fixage = to_str(data.get("fixage"), "%0.0f s")
return "%s / %s" % (up_age, fixage)
+ def get_dops(xkey):
+ pdop = to_str(data.get("pdop"), "%1.1f")
+ hdop = to_str(data.get("hdop"), "%1.1f")
+ vdop = to_str(data.get("vdop"), "%1.1f")
+ return f"{pdop} / {hdop} / {vdop}"
+
mode2fix = {
"2": "2 D",
"3": "3 D",
@@ -415,19 +444,19 @@
# Mapping: Data key, description, converter func
order = [
("mode", "Fix type", lambda x: mode2fix.get(x, "No Fix")),
- ("mode_indicator", "Modes (GP,GL,GA)", lambda x: str(x)),
+ ("mode_indicator", "Modes (GP,GL,GA)",
+ lambda x: str(x) if x is not None else "n/a"),
("actives", "Active / in use sats", get_actives),
("visibles", "Receiving sats", lambda x: str(len(
- list(r for r in x if r['snr'] > 0.0)))),
+ [r for r in x if r['snr'] > 0.0]))),
("visibles", "Visible sats", lambda x: str(len(x))),
# ("fixage", "Age of fix", lambda x: to_str(x, "%0.0f s")),
("fixage", "Age of update / fix", get_ages),
("systime", "Sys. Time", lambda x: x.strftime(utcfmt)),
- ("latlon", "Latitude",
- lambda x: "%0.6f" % x[0] if x else "-"),
- ("latlon", "Longitude",
- lambda x: "%0.6f" % x[1] if x else "-"),
- ("altitude", "Altitude", lambda x: to_str(x, "%0.1f m")),
+ ("latlon", "Latitude", lambda x: "%0.6f" % x[0] if x else "-"),
+ ("latlon", "Longitude", lambda x: "%0.6f" % x[1] if x else "-"),
+ ("altitude", "Altitude", lambda x: to_str(x, "%0.1f m")),
+ ("geoid_sep", "Geoidal separation", lambda x: to_str(x, "%0.1f m")),
# ("fixtime", "Time of fix",
# lambda x: x.strftime(utcfmt) if x else "-"),
# ("date", "Date of fix",
@@ -436,9 +465,7 @@
("true_course", "True Course",
lambda x: to_str(x, "%0.1f deg ")
+ (bearing_to_arrow(x) if x is not None else "")),
- ("pdop", "PDOP", lambda x: to_str(x)),
- ("hdop", "HDOP", lambda x: to_str(x)),
- ("vdop", "VDOP", lambda x: to_str(x)),
+ ("pdop", "PDOP/HDOP/VDOP", get_dops),
]
descs = []
vals = []
@@ -471,10 +498,9 @@
self.last_mode = mode
def set_speedlabel(self, speed, bearing=None):
- spd = str(int(3.6*speed)) if speed else "-"
+ spd = str(int(3.6 * speed)) if speed else "-"
arrow = bearing_to_arrow(bearing) if bearing is not None else ""
- speedfmt = ('%s%s\n' +
- '%s')
+ speedfmt = '%s%s\n%s'
speedstr = speedfmt % (spd, arrow, "km/h")
self.speedlabel.set_markup(speedstr)
@@ -539,8 +565,14 @@
def update(self):
try:
nmeas = self.source.get()
+ if self.had_error:
+ self.log_msg("Getting updates")
+ self.main_box.set_sensitive(True)
+
+ self.had_error = False
+ data = nmea.parse(nmeas)
except Exception as e:
- fatal = False
+ nmeas = None
show_dialog = False
etext = str(e)
dtext = None
@@ -552,37 +584,29 @@
elif isinstance(e, ModemError):
dtext = "Modem error: " + str(e)
elif isinstance(e, NmeaSourceNotFoundError):
- if not self.source_lost:
+ if not self.had_error:
dtext = etext if etext else "Modem disappeared"
- self.source_lost = True
+ self.had_error = True
self.main_box.set_sensitive(False)
else:
dtext = etext if etext else "Unknown error"
- if show_dialog:
- dialog = Gtk.MessageDialog(
- parent=self.window, modal=True,
- message_type=Gtk.MessageType.ERROR,
- buttons=Gtk.ButtonsType.OK, text=dtext)
- dialog.set_title("Unrecoverable error" if fatal else "Error")
- dialog.run()
- dialog.destroy()
- if fatal:
- self.quit()
- return
- elif dtext is not None:
- self.log_msg(dtext)
- return
-
- if not nmeas:
- return
-
- if self.source_lost:
- self.log_msg("Modem appeared")
- self.main_box.set_sensitive(True)
-
- self.source_lost = False
+ if not self.had_error:
+ if show_dialog:
+ dialog = Gtk.MessageDialog(
+ parent=self.window, modal=True,
+ message_type=Gtk.MessageType.ERROR,
+ buttons=Gtk.ButtonsType.OK, text=dtext)
+ dialog.set_title("Error")
+ dialog.run()
+ dialog.destroy()
+ elif dtext is not None:
+ self.log_msg(dtext)
+ self.had_error = True
+ if self.last_data is None:
+ return
+ else:
+ data = self.last_data
- data = nmea.parse(nmeas)
data["updateage"] = ((time.time() - self.last_update)
if self.last_update else None)
@@ -603,7 +627,7 @@
# log
mode = data["mode"]
- mode = int(mode) if mode else 0
+ mode = int(mode) if mode else self.last_mode
if mode != self.last_mode:
if mode > 1:
self.log_msg(f"Got lock, mode: {mode}")
diff -Nru satellite-gtk-0.3.1/satellite/__init__.py satellite-gtk-0.4.2/satellite/__init__.py
--- satellite-gtk-0.3.1/satellite/__init__.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/__init__.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
-__version__ = "0.3.1"
+__version__ = "0.4.2"
diff -Nru satellite-gtk-0.3.1/satellite/__main__.py satellite-gtk-0.4.2/satellite/__main__.py
--- satellite-gtk-0.3.1/satellite/__main__.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/__main__.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,4 +1,4 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
import sys
diff -Nru satellite-gtk-0.3.1/satellite/mm_glib_source.py satellite-gtk-0.4.2/satellite/mm_glib_source.py
--- satellite-gtk-0.3.1/satellite/mm_glib_source.py 1970-01-01 00:00:00.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/mm_glib_source.py 2023-09-23 11:31:05.000000000 +0000
@@ -0,0 +1,158 @@
+# Copyright 2023 Teemu Ikonen
+# SPDX-License-Identifier: GPL-3.0-only
+
+import re
+
+import gi
+from pynmea2.nmea import NMEASentence
+
+from satellite.nmeasource import ( # noqa: E402
+ ModemError,
+ ModemLockedError,
+ ModemNoNMEAError,
+ NmeaSource,
+ NmeaSourceNotFoundError,
+)
+
+gi.require_version('ModemManager', '1.0')
+from gi.repository import Gio, ModemManager # noqa: E402, I100
+
+
+class ModemManagerGLibNmeaSource(NmeaSource):
+
+ def __init__(self, update_callback, quirks=[], **kwargs):
+ super().__init__(update_callback, **kwargs)
+ self.bus = None
+ self.manager = None
+ self.modem = None
+ self.mlocation = None
+ self.old_refresh_rate = None
+ self.old_sources_enabled = None
+ self.old_signals_location = None
+ self.location_updated = None
+ self.quirks = set(quirks)
+
+ def initialize(self):
+ # If reinitializing, disconnect old update cb
+ if self.mlocation is not None:
+ self.mlocation.disconnect_by_func(self.update_callback)
+ self.bus = Gio.bus_get_sync(Gio.BusType.SYSTEM, None)
+ self.manager = ModemManager.Manager.new_sync(
+ self.bus, Gio.DBusObjectManagerClientFlags.DO_NOT_AUTO_START, None)
+ if self.manager.get_name_owner() is None:
+ raise NmeaSourceNotFoundError("ModemManager is not running")
+ objs = self.manager.get_objects()
+ if objs:
+ self.modem = objs[0].get_modem()
+ self.mlocation = objs[0].get_modem_location()
+ else:
+ raise NmeaSourceNotFoundError("No Modems Found")
+ self.manufacturer = self.modem.get_manufacturer()
+ self.model = self.modem.get_model()
+ self.revision = self.modem.get_revision()
+
+ if 'detect' in self.quirks:
+ self.quirks.remove('detect')
+ if (self.model.startswith('QUECTEL')
+ and self.manufacturer == 'QUALCOMM INCORPORATED'):
+ self.quirks.add('QuectelTalker')
+ # Detect SDM845 GNSS unit and disable MSB assistance,
+ # which causes stalling at startup due to some bug somewhere
+ if (self.manufacturer == 'QUALCOMM INCORPORATED'
+ and self.model == '0'
+ and self.revision.find('SDM845') >= 0):
+ self.quirks.add('NoMSB')
+
+ try:
+ state = self.modem.get_state()
+ if int(state) > 0:
+ if self.old_refresh_rate is None:
+ self.old_refresh_rate = self.mlocation.props.gps_refresh_rate
+ if self.old_sources_enabled is None:
+ self.old_sources_enabled = self.mlocation.props.enabled
+ if self.old_signals_location is None:
+ self.old_signals_location = self.mlocation.props.signals_location
+ caps = self.mlocation.get_capabilities()
+ if not caps & ModemManager.ModemLocationSource.GPS_NMEA:
+ raise NmeaSourceNotFoundError(
+ "Modem does not support NMEA")
+ enable = ModemManager.ModemLocationSource.GPS_NMEA
+ if (caps & ModemManager.ModemLocationSource.AGPS_MSB
+ and 'NoMSB' not in self.quirks):
+ enable |= ModemManager.ModemLocationSource.AGPS_MSB
+ self.mlocation.setup_sync(enable, True, None)
+ else:
+ raise ModemError("Modem state is: %d" % state)
+ except AttributeError as e:
+ if state == ModemManager.ModemState.LOCKED:
+ raise ModemLockedError from e
+ else:
+ raise e
+ except gi.repository.GLib.GError as e:
+ # Ignore error on AGPS enablement by this hack
+ if 'agps-msb' not in str(e):
+ raise e
+
+ self.mlocation.set_gps_refresh_rate_sync(self.refresh_rate, None)
+ self.mlocation.connect('notify::location', self.update_callback)
+
+ self.initialized = True
+
+ def _really_get(self):
+ if not self.initialized:
+ self.initialize()
+ try:
+ loc = self.mlocation.get_signaled_gps_nmea()
+ except Exception as e:
+ self.initialized = False
+ raise e
+
+ if loc is None:
+ raise ModemNoNMEAError
+
+ nmeas = loc.get_traces()
+ if nmeas is None:
+ self.initialized = False
+ raise ModemNoNMEAError
+
+ if 'QuectelTalker' in self.quirks:
+ nmeas = self.quectel_talker_quirk(nmeas)
+
+ return '\r\n'.join(nmeas)
+
+ def close(self):
+ if self.mlocation is None:
+ return
+ try:
+ self.mlocation.disconnect_by_func(self.update_callback)
+ except TypeError:
+ pass # Ignore error when nothing is connected
+ if self.old_sources_enabled is not None:
+ self.mlocation.setup_sync(
+ ModemManager.ModemLocationSource(self.old_sources_enabled),
+ self.old_signals_location, None)
+ if self.old_refresh_rate is not None:
+ self.mlocation.set_gps_refresh_rate_sync(self.old_refresh_rate, None)
+
+ def quectel_talker_quirk(self, nmeas):
+ pq_re = re.compile(r"""
+ ^\s*\$?
+ (?PPQ)
+ (?P\w{3})
+ (?P[^*]*)
+ (?:[*](?P[A-F0-9]{2}))$""", re.VERBOSE)
+ out = []
+ for nmea in (n for n in nmeas if n):
+ mo = pq_re.match(nmea)
+ if mo:
+ # The last extra data field is Signal ID, these are
+ # 1 = GPS, 2 = Glonass, 3 = Galileo, 4 = BeiDou, 5 = QZSS
+ # Determine talker from Signal ID
+ talker = 'QZ' if mo.group('data').endswith('5') else 'BD'
+ # Fake talker and checksum
+ fake = talker + "".join(mo.group(2, 3))
+ out.append('$' + fake + "*%02X" % NMEASentence.checksum(fake))
+ else:
+ out.append(nmea)
+
+ return out
diff -Nru satellite-gtk-0.3.1/satellite/modem_manager_defs.py satellite-gtk-0.4.2/satellite/modem_manager_defs.py
--- satellite-gtk-0.3.1/satellite/modem_manager_defs.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/modem_manager_defs.py 1970-01-01 00:00:00.000000000 +0000
@@ -1,31 +0,0 @@
-# Copyright 2021-2022 Teemu Ikonen
-# SPDX-License-Identifier: GPL-3.0-only
-
-# flake8: noqa
-
-# See /usr/include/ModemManager/ModemManager-enums.h in modemmanager-dev
-MM_MODEM_LOCATION_SOURCE_NONE = 0
-MM_MODEM_LOCATION_SOURCE_3GPP_LAC_CI = 1 << 0
-MM_MODEM_LOCATION_SOURCE_GPS_RAW = 1 << 1
-MM_MODEM_LOCATION_SOURCE_GPS_NMEA = 1 << 2
-MM_MODEM_LOCATION_SOURCE_CDMA_BS = 1 << 3
-MM_MODEM_LOCATION_SOURCE_GPS_UNMANAGED = 1 << 4
-MM_MODEM_LOCATION_SOURCE_AGPS_MSA = 1 << 5
-MM_MODEM_LOCATION_SOURCE_AGPS_MSB = 1 << 6
-
-MM_MODEM_LOCATION_ASSISTANCE_DATA_TYPE_NONE = 0
-MM_MODEM_LOCATION_ASSISTANCE_DATA_TYPE_XTRA = 1 << 0
-
-MM_MODEM_STATE_FAILED = -1
-MM_MODEM_STATE_UNKNOWN = 0
-MM_MODEM_STATE_INITIALIZING = 1
-MM_MODEM_STATE_LOCKED = 2
-MM_MODEM_STATE_DISABLED = 3
-MM_MODEM_STATE_DISABLING = 4
-MM_MODEM_STATE_ENABLING = 5
-MM_MODEM_STATE_ENABLED = 6
-MM_MODEM_STATE_SEARCHING = 7
-MM_MODEM_STATE_REGISTERED = 8
-MM_MODEM_STATE_DISCONNECTING = 9
-MM_MODEM_STATE_CONNECTING = 10
-MM_MODEM_STATE_CONNECTED = 11
diff -Nru satellite-gtk-0.3.1/satellite/nmea.py satellite-gtk-0.4.2/satellite/nmea.py
--- satellite-gtk-0.3.1/satellite/nmea.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/nmea.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,10 +1,11 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
import datetime
-import pynmea2
import re
+import pynmea2
+
MS_PER_KNOT = 0.514444
lastfix_dt = None
@@ -28,7 +29,7 @@
def iget(key, default=None):
def fn(d):
try:
- return int(d.get(key))
+ return int(d.get(key, default))
except ValueError:
return default
return fn
@@ -61,9 +62,9 @@
lat_min = float(lat[2:])
lon_deg = float(lon[:3])
lon_min = float(lon[3:])
- flat = lat_deg + lat_min/60
+ flat = lat_deg + lat_min / 60
flat = -1 * flat if lat_dir == 'S' else flat
- flon = lon_deg + lon_min/60
+ flon = lon_deg + lon_min / 60
flon = -1 * flon if lon_dir == 'W' else flon
return (flat, flon)
@@ -98,12 +99,10 @@
'GGA': get_altitude_gga,
'GNS': fget('altitude'),
},
- "fixtime": {
+ "fixtime": { # Time of position report
'RMC': get_time,
- 'GGA': get_time,
- },
- "time": { # Reported also when no fix
'GNS': get_time,
+ 'GGA': get_time,
},
"date": {
'RMC': get_date,
@@ -131,6 +130,7 @@
},
"num_sats": {
'GNS': iget('num_sats', default=0),
+ 'GGA': iget('num_sats', default=0),
},
"pdop": {
'GSA': fget('pdop'),
@@ -143,7 +143,8 @@
"vdop": {
'GSA': fget('vdop'),
},
- "geo_sep": {
+ "geoid_sep": {
+ 'GGA': fget('geo_sep'),
'GNS': fget('geo_sep'),
},
"sel_mode": {
@@ -182,7 +183,7 @@
return float(s) if s else empty_val
def add_prn_prefix(prns, talker, always=always_add_prefix):
- """Add constellation prefix to PRN string"""
+ """Add constellation prefix to PRN string."""
beidou_prefix = "C"
galileo_prefix = "E"
glonass_prefix = "R"
@@ -227,7 +228,7 @@
'snr': fl(getattr(msg, f'snr_{n}', None), 0.0),
})
elif isinstance(msg, pynmea2.types.GSA):
- for n in range(1, 12+1):
+ for n in range(1, 12 + 1):
prns = getattr(msg, f'sv_id{n:02d}')
if prns and prns.isdigit():
actives.append(add_prn_prefix(prns, msg.talker))
@@ -248,13 +249,13 @@
}
out.update({k: msg_get(msgs, k) for k in getters.keys()})
- datenow = datetime.datetime.utcnow()
+ datenow = datetime.datetime.now(datetime.timezone.utc)
fixtime = out.get('fixtime')
fixdate = out.get('date')
if fixdate is None and fixtime is not None:
# We have a fix but no RMC sentence
fixdate = datenow.date()
- fixdt = (datetime.datetime.combine(fixdate, fixtime)
+ fixdt = (datetime.datetime.combine(fixdate, fixtime, datetime.timezone.utc)
if (fixtime and fixdate) else None)
out["datetime"] = fixdt
out["systime"] = datenow
diff -Nru satellite-gtk-0.3.1/satellite/nmeasource.py satellite-gtk-0.4.2/satellite/nmeasource.py
--- satellite-gtk-0.3.1/satellite/nmeasource.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/nmeasource.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,12 +1,8 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
-import re
-import satellite.modem_manager_defs as mm
import os.path
import socket
-from pydbus import SystemBus
-from pynmea2.nmea import NMEASentence
from gi.repository import GLib
@@ -73,11 +69,12 @@
def on_read_data_available(self, io_channel, condition, **unused):
self.update_callback()
+ return True
def initialize(self):
- if self.socket_file_path is None or \
- not os.path.exists(self.socket_file_path):
- return
+ if (self.socket_file_path is None
+ or not os.path.exists(self.socket_file_path)):
+ raise FileNotFoundError(f"Could not open socket {self.socket_file_path}")
self.s = socket.socket(socket.AF_UNIX,
socket.SOCK_NONBLOCK | socket.SOCK_STREAM)
@@ -113,118 +110,7 @@
super().__init__(update_callback,
socket_file_path='/var/run/gnss-share.sock',
**kwargs)
-
-
-class ModemManagerNmeaSource(NmeaSource):
- def __init__(self, update_callback, **kwargs):
- super().__init__(update_callback, **kwargs)
- self.bus = SystemBus()
- self.manager = self.bus.get('.ModemManager1')
- self.modem = None
- self.old_refresh_rate = None
- self.old_sources_enabled = None
- self.old_signals = None
- self.location_updated = None
-
- def initialize(self):
- objs = self.manager.GetManagedObjects()
- mkeys = list(objs.keys())
- if mkeys:
- mstr = mkeys[0]
- else:
- raise NmeaSourceNotFoundError("No Modems Found")
- info = objs[mstr]['org.freedesktop.ModemManager1.Modem']
- self.manufacturer = info.get('Manufacturer')
- self.model = info.get('Model')
- self.revision = info.get('Revision')
- self.modem = self.bus.get('.ModemManager1', mstr)
-
- try:
- if self.modem.State > 0:
- if self.old_refresh_rate is None:
- self.old_refresh_rate = self.modem.GpsRefreshRate
- if self.old_sources_enabled is None:
- self.old_sources_enabled = self.modem.Enabled
- if self.old_signals is None:
- self.old_signals = self.modem.SignalsLocation
- cap = self.modem.Capabilities
- if (cap & mm.MM_MODEM_LOCATION_SOURCE_GPS_NMEA) == 0:
- raise NmeaSourceNotFoundError(
- "Modem does not support NMEA")
- self.modem.Setup(
- (mm.MM_MODEM_LOCATION_SOURCE_GPS_NMEA
- | (cap & mm.MM_MODEM_LOCATION_SOURCE_AGPS_MSB)),
- True)
- else:
- raise ModemError("Modem state is: %d" % self.modem.State)
- except AttributeError as e:
- if self.modem.State == mm.MM_MODEM_STATE_LOCKED:
- raise ModemLockedError from e
- else:
- raise ModemError from e
- except Exception as e:
- raise e
-
- self.modem.SetGpsRefreshRate(self.refresh_rate)
- self.location_updated = self.bus.subscribe(
- sender='org.freedesktop.ModemManager1',
- iface='org.freedesktop.DBus.Properties',
- signal='PropertiesChanged',
- arg0='org.freedesktop.ModemManager1.Modem.Location',
- signal_fired=self.update_callback)
- self.initialized = True
-
- def _really_get(self):
- if not self.initialized:
- self.initialize()
- try:
- loc = self.modem.GetLocation()
- except Exception as e:
- self.initialized = False
- raise e
-
- retval = loc.get(mm.MM_MODEM_LOCATION_SOURCE_GPS_NMEA)
- if retval is None:
- self.initialized = False
- raise ModemNoNMEAError
- return retval
-
- def close(self):
- if self.location_updated is not None:
- self.location_updated.disconnect()
- if self.old_sources_enabled is not None:
- self.modem.Setup(self.old_sources_enabled, self.old_signals)
- if self.old_refresh_rate is not None:
- self.modem.SetGpsRefreshRate(self.old_refresh_rate)
-
-
-class QuectelNmeaSource(ModemManagerNmeaSource):
-
- def _really_get(self):
- return self.fix_talker(super()._really_get())
-
- def fix_talker(self, nmeas):
- pq_re = re.compile(r'''
- ^\s*\$?
- (?PPQ)
- (?P\w{3})
- (?P[^*]*)
- (?:[*](?P[A-F0-9]{2}))$''', re.VERBOSE)
- out = []
- for nmea in (n for n in nmeas.split('\r\n') if n):
- mo = pq_re.match(nmea)
- if mo:
- # The last extra data field is Signal ID, these are
- # 1 = GPS, 2 = Glonass, 3 = Galileo, 4 = BeiDou, 5 = QZSS
- # Determine talker from Signal ID
- talker = 'QZ' if mo.group('data').endswith('5') else 'BD'
- # Fake talker and checksum
- fake = talker + "".join(mo.group(2, 3))
- out.append('$' + fake + "*%02X" % NMEASentence.checksum(fake))
- else:
- out.append(nmea)
-
- return "\r\n".join(out)
+ self.manufacturer = "gnss-share"
class ReplayNmeaSource(NmeaSource):
diff -Nru satellite-gtk-0.3.1/satellite/quectel.py satellite-gtk-0.4.2/satellite/quectel.py
--- satellite-gtk-0.3.1/satellite/quectel.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/quectel.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,8 +1,7 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
import re
-
from datetime import datetime, timezone
from .util import (
diff -Nru satellite-gtk-0.3.1/satellite/util.py satellite-gtk-0.4.2/satellite/util.py
--- satellite-gtk-0.3.1/satellite/util.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/util.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,11 +1,10 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
-import gi
import os
-
from datetime import datetime, timezone
+import gi
gi.require_version('Gdk', '3.0')
from gi.repository import Gdk # noqa: E402
@@ -16,15 +15,13 @@
def have_touchscreen():
- """Return True if the default seat of default display has touch capability
- """
+ """Return True if the default seat of default display has touch capability."""
return bool(Gdk.Display.get_default_seat(
Gdk.Display.get_default()).get_capabilities() & Gdk.SeatCapabilities.TOUCH)
def datetime_from_gpstime(week, millisecs, fix_week=False):
- """Return a datetime object formed from GPS week number and
- milliseconds from week start.
+ """Return a datetime from GPS week number and milliseconds from week start.
If fix_week is True, set the bits above 10 in week number from
current date, see
@@ -38,7 +35,7 @@
def gpstime_from_datetime(dt):
- """Return a (gps_week, millisec) tuple from a datetime object"""
+ """Return a (gps_week, millisec) tuple from a datetime object."""
if dt < gps_epoch:
raise ValueError("Time cannot be less than GPS epoch")
ts = dt.timestamp()
@@ -51,7 +48,7 @@
def unique_filename(namestem, ext, timestamp=False):
if timestamp:
namestem += "-" + datetime.now().isoformat(
- '_', 'seconds').replace(':', '.')
+ '_', 'seconds').replace(':', '.')
name = None
for count in ('~%d' % n if n > 0 else '' for n in range(100)):
test = namestem + count + ext
@@ -77,7 +74,7 @@
'\u2196',
'\u2191',
]
- edges = list(22.5 + 45.0 * n for n in range(0, 8)) + [360.0]
+ edges = [22.5 + 45.0 * n for n in range(0, 8)] + [360.0]
angle = bearing - (bearing // 360) * 360
index = next(ind for (ind, e) in enumerate(edges) if angle < e)
diff -Nru satellite-gtk-0.3.1/satellite/widgets.py satellite-gtk-0.4.2/satellite/widgets.py
--- satellite-gtk-0.3.1/satellite/widgets.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/satellite/widgets.py 2023-09-23 11:31:05.000000000 +0000
@@ -1,10 +1,9 @@
-# Copyright 2021-2022 Teemu Ikonen
+# Copyright 2021-2023 Teemu Ikonen
# SPDX-License-Identifier: GPL-3.0-only
-import gi
-
import importlib.resources as resources
+import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Gdk', '3.0')
from gi.repository import Gtk # noqa: E402
@@ -18,8 +17,7 @@
height Number of lines in the generated bar chart
width Width of the generated bar chart in chars
"""
- sdata = list((d[0] if d[0] else '',
- int(d[1]) if d[1] else 0) for d in data)
+ sdata = [(d[0] if d[0] else '', int(d[1]) if d[1] else 0) for d in data]
sdata.sort(key=lambda x: x[1], reverse=True)
dstr = ''
@@ -41,14 +39,14 @@
cmax_xaxis = cmaxbar + 3
for d in sdata[:barlines]:
block = '\u2585' if d[0] in highlights else '='
- dstr += "%3s\u2502%s %d\n" % (d[0], block*int(scale*d[1]), d[1])
+ dstr += "%3s\u2502%s %d\n" % (d[0], block * int(scale * d[1]), d[1])
if barlines < len(sdata):
dstr += " \u256a\n"
elif (len(sdata) - axislines) < height:
# Add empty lines to y-axis
dstr += ' \u2502\n' * (height - len(sdata) - axislines)
- dstr += " \u251c" + '\u2500'*(cmax_xaxis) + '\u2524\n'
- dstr += " 0" + ' '*(cmax_xaxis - 1) + str(max_xaxis)
+ dstr += " \u251c" + '\u2500' * (cmax_xaxis) + '\u2524\n'
+ dstr += " 0" + ' ' * (cmax_xaxis - 1) + str(max_xaxis)
return dstr
diff -Nru satellite-gtk-0.3.1/setup.cfg satellite-gtk-0.4.2/setup.cfg
--- satellite-gtk-0.3.1/setup.cfg 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/setup.cfg 2023-09-23 11:31:05.000000000 +0000
@@ -1,3 +1,8 @@
[flake8]
exclude=.git,__pycache__,build
max-line-length=88
+ignore = B902, BLK100, CCR001, CNL100, D1, I201, Q000, W503
+
+[pycodestyle]
+count=1
+max-line-length = 88
diff -Nru satellite-gtk-0.3.1/setup.py satellite-gtk-0.4.2/setup.py
--- satellite-gtk-0.3.1/setup.py 2022-11-17 16:58:42.000000000 +0000
+++ satellite-gtk-0.4.2/setup.py 2023-09-23 11:31:05.000000000 +0000
@@ -29,7 +29,7 @@
"Bug Tracker": "https://codeberg.org/tpikonen/satellite/issues",
},
classifiers=[
- "Development Status :: 3 - Alpha",
+ "Development Status :: 4 - Beta",
"Environment :: X11 Applications :: GTK",
"Intended Audience :: End Users/Desktop",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",