Skip to content

Commit 62b78a3

Browse files
committed
fix: ensure result.timestamp present for Go server schema validation
Go CSAPI server validates that observation results contain all fields defined in the datastream schema. Publishers were popping 'timestamp' from the result (SensorHub auto-fills from phenomenonTime), but Go server requires it explicitly. Now re-adds timestamp from phenomenonTime when missing. Also adds Go workaround to BuoyCAM and NIMS publishers.
1 parent 3a02268 commit 62b78a3

8 files changed

Lines changed: 45 additions & 14 deletions

File tree

publishers/aviation_wx/aviation_wx_publisher.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -288,8 +288,10 @@ def _post_observation(self, ds_id: str, obs: dict):
288288
for key, val in list(r.items()):
289289
if val == "NaN":
290290
r[key] = 0.0
291-
# Coerce numeric timestamp to string
292-
if "timestamp" in r and not isinstance(r["timestamp"], str):
291+
# Go server requires timestamp in result (schema validation)
292+
if "timestamp" not in r:
293+
r["timestamp"] = obs.get("phenomenonTime", "")
294+
elif not isinstance(r["timestamp"], str):
293295
r["timestamp"] = str(r["timestamp"])
294296

295297
url = f"{self._base_url}/datastreams/{ds_id}/observations"

publishers/coops/coops_publisher.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,8 +310,10 @@ def _post_observation(self, ds_id: str, obs: dict):
310310
for key, val in list(r.items()):
311311
if val == "NaN":
312312
r[key] = 0.0
313-
# Coerce numeric timestamp to string
314-
if "timestamp" in r and not isinstance(r["timestamp"], str):
313+
# Go server requires timestamp in result (schema validation)
314+
if "timestamp" not in r:
315+
r["timestamp"] = obs.get("phenomenonTime", "")
316+
elif not isinstance(r["timestamp"], str):
315317
r["timestamp"] = str(r["timestamp"])
316318

317319
url = f"{self._base_url}/datastreams/{ds_id}/observations"

publishers/iss/iss_publisher.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,13 @@ def publish_obs(self, obs: dict) -> bool:
255255
import ssl
256256
url = f"{self._base_url}/datastreams/{self._ds_id}/observations"
257257

258-
# Go server: coerce numeric timestamp to string
259-
if self._is_go_server:
260-
r = obs.get("result", {})
261-
if "timestamp" in r and not isinstance(r["timestamp"], str):
258+
# Go server workarounds
259+
if self._is_go_server:
260+
r = obs.get("result", {})
261+
# Go server requires timestamp in result (schema validation)
262+
if "timestamp" not in r:
263+
r["timestamp"] = obs.get("phenomenonTime", "")
264+
elif not isinstance(r["timestamp"], str):
262265
r["timestamp"] = str(r["timestamp"])
263266

264267
body = json.dumps(obs).encode()

publishers/ndbc/ndbc_buoycam_publisher.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,15 @@ def connect_with_retry(self, max_attempts=10, base_delay=5.0, max_delay=120.0):
212212

213213
def _post_observation(self, ds_id: str, obs: dict):
214214
"""POST an observation to the server."""
215+
# Go server workarounds
216+
if self._is_go_server:
217+
r = obs.get("result", {})
218+
# Go server requires timestamp in result (schema validation)
219+
if "timestamp" not in r:
220+
r["timestamp"] = obs.get("phenomenonTime", "")
221+
elif not isinstance(r["timestamp"], str):
222+
r["timestamp"] = str(r["timestamp"])
223+
215224
url = f"{self._base_url}/datastreams/{ds_id}/observations"
216225
body = json.dumps(obs).encode()
217226

publishers/ndbc/ndbc_publisher.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,10 @@ def _post_observation(self, ds_id: str, obs: dict):
255255
for key, val in list(r.items()):
256256
if val == "NaN":
257257
r[key] = 0.0
258-
# Coerce numeric timestamp to string
259-
if "timestamp" in r and not isinstance(r["timestamp"], str):
258+
# Go server requires timestamp in result (schema validation)
259+
if "timestamp" not in r:
260+
r["timestamp"] = obs.get("phenomenonTime", "")
261+
elif not isinstance(r["timestamp"], str):
260262
r["timestamp"] = str(r["timestamp"])
261263

262264
url = f"{self._base_url}/datastreams/{ds_id}/observations"

publishers/nws/nws_publisher.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,10 @@ def _post_observation(self, ds_id: str, obs: dict):
226226
for key, val in list(r.items()):
227227
if val == "NaN":
228228
r[key] = 0.0
229-
# Coerce numeric timestamp to string
230-
if "timestamp" in r and not isinstance(r["timestamp"], str):
229+
# Go server requires timestamp in result (schema validation)
230+
if "timestamp" not in r:
231+
r["timestamp"] = obs.get("phenomenonTime", "")
232+
elif not isinstance(r["timestamp"], str):
231233
r["timestamp"] = str(r["timestamp"])
232234

233235
url = f"{self._base_url}/datastreams/{ds_id}/observations"

publishers/usgs_nims/usgs_nims_publisher.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ def connect_with_retry(self, max_attempts=10, base_delay=5.0, max_delay=120.0):
235235

236236
def _post_observation(self, ds_id: str, obs: dict):
237237
"""POST an observation to the server."""
238+
# Go server workarounds
239+
if self._is_go_server:
240+
r = obs.get("result", {})
241+
# Go server requires timestamp in result (schema validation)
242+
if "timestamp" not in r:
243+
r["timestamp"] = obs.get("phenomenonTime", "")
244+
elif not isinstance(r["timestamp"], str):
245+
r["timestamp"] = str(r["timestamp"])
246+
238247
url = f"{self._base_url}/datastreams/{ds_id}/observations"
239248
body = json.dumps(obs).encode()
240249

publishers/usgs_water/usgs_water_publisher.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -250,8 +250,10 @@ def _post_observation(self, ds_id: str, obs: dict):
250250
# Go server workarounds
251251
if self._is_go_server:
252252
r = obs.get("result", {})
253-
# Coerce numeric timestamp to string
254-
if "timestamp" in r and not isinstance(r["timestamp"], str):
253+
# Go server requires timestamp in result (schema validation)
254+
if "timestamp" not in r:
255+
r["timestamp"] = obs.get("phenomenonTime", "")
256+
elif not isinstance(r["timestamp"], str):
255257
r["timestamp"] = str(r["timestamp"])
256258

257259
url = f"{self._base_url}/datastreams/{ds_id}/observations"

0 commit comments

Comments
 (0)