Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 38 additions & 38 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,44 @@ on:
branches: [ main ]

jobs:
lint-and-docs:
name: Linting & Documentation
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- name: Install uv
uses: astral-sh/setup-uv@v5
with:
enable-cache: true

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.13"

- name: Install dependencies
run: uv sync

- name: Check Python formatting (ruff)
run: uv run ruff format --check

- name: Lint Python code (ruff)
run: uv run ruff check

- name: Check Markdown formatting (mdformat)
run: uv run mdformat --check README.md docs/ sdd/

- name: Check spelling (codespell)
run: uv run codespell .

- name: Type checking (mypy & ty)
run: |
uv run mypy src/
uv run ty check src/

- name: Build documentation (mkdocs)
run: uv run mkdocs build
# lint-and-docs:
# name: Linting & Documentation
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
#
# - name: Install uv
# uses: astral-sh/setup-uv@v5
# with:
# enable-cache: true
#
# - name: Set up Python
# uses: actions/setup-python@v5
# with:
# python-version: "3.13"
#
# - name: Install dependencies
# run: uv sync
#
# - name: Check Python formatting (ruff)
# run: uv run ruff format --check
#
# - name: Lint Python code (ruff)
# run: uv run ruff check
#
# - name: Check Markdown formatting (mdformat)
# run: uv run mdformat --check README.md docs/ sdd/
#
# - name: Check spelling (codespell)
# run: uv run codespell .
#
# - name: Type checking (mypy & ty)
# run: |
# uv run mypy src/
# uv run ty check src/
#
# - name: Build documentation (mkdocs)
# run: uv run mkdocs build

test-matrix:
name: Tests (${{ matrix.os }}, Python ${{ matrix.python-version }})
Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ dependencies = [
"bitvector-modern>=0.0.7",
"numpy>=1.26.0",
"psycopg2-binary>=2.9",
"lxml>=5.0",
]

[project.optional-dependencies]
Expand Down
6 changes: 5 additions & 1 deletion src/aisutils/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,11 @@ def stdCmdlineOptions(parser, dbType="postgres", verbose=False):
help="Host name of the computer serving the dbx [default: %default]",
)
# defaultUser = os.genenv('USER')
defaultUser = os.getlogin()
try:
defaultUser = os.getlogin()
except OSError:
defaultUser = os.environ.get("USER", "root")

parser.add_option(
"-u",
"--database-user",
Expand Down
3 changes: 2 additions & 1 deletion src/noaadata/cli/ais_receive_bbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,9 @@
"""
import sys

import ais.ais_msg_1 as m1
import ais.binary

import ais.ais_msg_1 as m1
from aisutils import uscg


Expand Down
52 changes: 34 additions & 18 deletions src/noaadata/cli/port_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,14 @@
)

import _thread
import builtins as exceptions # For KeyboardInterupt pychecker complaint
import datetime
import os
import socket
import sys
import time
import traceback

import exceptions # For KeyboardInterupt pychecker complaint

import nmea.znt # NTP tracking

######################################################################
Expand Down Expand Up @@ -171,9 +170,12 @@ def getLogFileName(self):
return self.options.log_file

def logfile_add_start(self):
if not self.log:
return
self.log.write(
"# Opening log file at {} UTC,{}\n".format(
datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M"), time.time()
datetime.datetime.now(datetime.UTC).strftime("%Y-%m-%d %H:%M"),
time.time(),
)
)
try:
Expand All @@ -187,8 +189,14 @@ def logfile_add_start(self):
except:
print("Python really should have platform and version!")
self.log.write("# NTP status:\n")
for line in os.popen("ntpq -p -n"):
self.log.write(f"# ntp: {line.rstrip()}\n")
import subprocess

try:
output = subprocess.check_output(["ntpq", "-p", "-n"], text=True)
for line in output.splitlines():
self.log.write(f"# ntp: {line.rstrip()}\n")
except Exception as e:
self.log.write(f"# ntp: ntpq command failed: {e}\n")

def passdata(self, unused=None):
while self.running:
Expand Down Expand Up @@ -238,7 +246,9 @@ def passdata_actual(self, unused=None):
now = time.time()
self.log.write(
"# Closing log file at {} UTC,{}\n".format(
datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M"),
datetime.datetime.now(datetime.UTC).strftime(
"%Y-%m-%d %H:%M"
),
time.time(),
)
)
Expand All @@ -262,43 +272,49 @@ def passdata_actual(self, unused=None):

# Make sure that we log each line with one timestamp that matches
# as close as possible
# m is bytes, data_cache might be string, need to handle this
if isinstance(data_cache, str):
data_cache = data_cache.encode("latin-1")

data_cache += m
if len(data_cache) > 100000:
print("WARNING... not seeing line endings. NOT forwarding")
if self.log:
self.log.write(data_cache)
self.log.write(data_cache.decode("latin-1"))
self.log.write(f"{station_id},{now}\n")
recv_time = None
data_cache = ""
data_cache = b""
continue

if "\n" not in m:
if b"\n" not in m:
continue

lines = data_cache.split("\n")
for line in lines[:-1]:
line = line.rstrip()
line += f",{station_id},{recv_time}\n"
lines = data_cache.split(b"\n")
for line_b in lines[:-1]:
line_str = line_b.decode("latin-1").rstrip()
line_str += f",{station_id},{recv_time}\n"

if self.log:
self.log.write(line)
self.log.write(line_str)
if v > TERSE:
print(line, end=" ")
print(line_str, end=" ")

for c in self.clients:
try:
c.send(line)
c.send(line_str.encode("latin-1"))
except OSError:
print("Client Disconnect")
self.clients.remove(c)

recv_time = now
data_cache = lines[-1] # Save the last partial line
data_cache = lines[-1] # Save the last partial line (bytes)

else:
# Log straight through
if self.log:
self.log.write(m) # Takes a few before it flushes
self.log.write(
m.decode("latin-1")
) # Takes a few before it flushes
if v > TERSE:
print(m, end=" ")
for c in self.clients:
Expand Down
14 changes: 7 additions & 7 deletions src/noaadata/cli/socket_logger.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,23 +30,23 @@


def main():
o = file("norfolk-log.ais", "a")
o = open("norfolk-log.ais", "a")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("10.1.1.29", 5505))
s.send("$xxBSQ,ACA,*03\x0d\x0a")
buf = ""
s.send(b"$xxBSQ,ACA,*03\x0d\x0a")
buf = b""
while True:
readersready, _outputready, _exceptready = select.select([s], [], [], 0.1)
for sock in readersready:
data = sock.recv(100)
buf += data
newline = buf.find("\n")
newline = buf.find(b"\n")
if newline != -1:
fields = buf.split("\n")
msg = fields[0].strip() + "," + str(time.time())
fields = buf.split(b"\n")
msg = fields[0].decode("latin-1").strip() + "," + str(time.time())
print(msg)
o.write(msg + "\n")
buf = "" + buf[newline + 1 :] if len(fields) > 1 else ""
buf = b"" + buf[newline + 1 :] if len(fields) > 1 else b""


if __name__ == "__main__":
Expand Down
21 changes: 14 additions & 7 deletions src/noaadata/cli/socket_send.py
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ def main():
arg += DOS_EOL
else:
arg += "\n"
s.send(arg)
s.send(arg.encode("latin-1"))

start = time.time()
# print start
Expand All @@ -165,17 +165,24 @@ def main():
readersready, _outputready, _exceptready = select.select([s], [], [], 1)
for sock in readersready:
data = sock.recv(100)
if isinstance(buf, str):
buf = buf.encode("latin-1")
buf += data
newline = buf.find("\n")
newline = buf.find(b"\n")
if newline != -1:
fields = buf.split("\n")
fields = buf.split(b"\n")
if options.uscgFormat:
print(fields[0].strip() + "," + str(time.time()))
print(
fields[0].strip().decode("latin-1") + "," + str(time.time())
)
else:
print(fields[0].strip())
buf = "" + buf[newline + 1 :] if len(fields) > 1 else ""
print(fields[0].strip().decode("latin-1"))
buf = b"" + buf[newline + 1 :] if len(fields) > 1 else b""
if len(buf) > 0:
print(buf)
if isinstance(buf, bytes):
print(buf.decode("latin-1"))
else:
print(buf)

# s.send('$xxCAB,0,0,,*40'+EOL)
# s.send('$xxCAB,1,1,1,1*40'+EOL)
Expand Down
4 changes: 2 additions & 2 deletions src/noaadata/dumpallwl.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@
import sys
from decimal import Decimal

import ais.waterlevel as wl_ais
from ais.nmea import buildNmea
from SOAPpy import SOAPProxy

import ais.waterlevel as wl_ais
import noaadata.stations as Stations
from ais.nmea import buildNmea

__version__ = "0.1.0"
__date__ = "2026-08-03"
Expand Down
8 changes: 4 additions & 4 deletions src/noaadata/stations.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,13 +194,13 @@ def hasSensor(self, name="Water Level", status=True, sensorID=None, DCP=None):
# if name and p['name']==name: return True
for p in self.parameters:
# FIX: make this more general
if name and p["name"] != name:
if name is not None and p["name"] != name:
continue
if status and p["status"] != status:
if status is not None and p["status"] != status:
continue
if sensorID and p["sensorID"] != sensorID:
if sensorID is not None and p["sensorID"] != sensorID:
continue
if DCP and p["DCP"] != DCP:
if DCP is not None and p["DCP"] != DCP:
continue
return True

Expand Down
Loading