temperature-sensor-scanner 2.0.0__tar.gz → 2.0.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,12 +1,13 @@
1
1
  name: Publish to PyPI and TestPyPI
2
2
 
3
- on: push
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
4
7
 
5
8
  jobs:
6
9
  build:
7
10
  name: Build distribution
8
- if: startsWith(github.ref, 'refs/tags/') # only build on tag pushes
9
-
10
11
  runs-on: ubuntu-latest
11
12
 
12
13
  steps:
@@ -34,7 +35,6 @@ jobs:
34
35
  publish-to-pypi:
35
36
  name: >-
36
37
  Publish to PyPI
37
- if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
38
38
  needs:
39
39
  - build
40
40
  runs-on: ubuntu-latest
@@ -55,7 +55,6 @@ jobs:
55
55
 
56
56
  publish-to-testpypi:
57
57
  name: Publish to TestPyPI
58
- if: startsWith(github.ref, 'refs/tags/') # only publish to PyPI on tag pushes
59
58
  needs:
60
59
  - build
61
60
  runs-on: ubuntu-latest
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: temperature-sensor-scanner
3
- Version: 2.0.0
3
+ Version: 2.0.1
4
4
  Summary: A tool to collect data from temperature sensors and emit it into InfluxDB 3
5
5
  Project-URL: Homepage, https://github.com/gene1wood/temperature-sensor-scanner
6
6
  Project-URL: Repository, https://github.com/gene1wood/temperature-sensor-scanner
@@ -9,7 +9,6 @@ License: GPL-3.0-or-later
9
9
  Requires-Python: >=3.10
10
10
  Requires-Dist: atc-mi-interface
11
11
  Requires-Dist: bleak
12
- Requires-Dist: influxdb3-python
13
12
  Requires-Dist: platformdirs
14
13
  Requires-Dist: pyyaml
15
14
  Description-Content-Type: text/markdown
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "temperature-sensor-scanner"
7
- version = "2.0.0"
7
+ version = "2.0.1"
8
8
  description = "A tool to collect data from temperature sensors and emit it into InfluxDB 3"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -15,7 +15,6 @@ authors = [
15
15
  dependencies = [
16
16
  "bleak",
17
17
  "atc-mi-interface",
18
- "influxdb3-python",
19
18
  "platformdirs",
20
19
  "PyYAML"
21
20
  ]
@@ -1,5 +1,4 @@
1
1
  bleak
2
2
  atc-mi-interface
3
- influxdb3-python
4
3
  platformdirs
5
4
  PyYAML
@@ -11,9 +11,10 @@ from atc_mi_interface import (
11
11
 
12
12
  # atc-mi-interface
13
13
  # https://github.com/pvvx/ATC_MiThermometer/tree/master/python-interface#decoding-and-encoding
14
- from influxdb_client_3 import InfluxDBClient3, Point # pip install influxdb3-python
15
14
 
16
15
  import sys
16
+ import urllib.parse
17
+ import urllib.request
17
18
  from pathlib import Path
18
19
 
19
20
  import yaml # pip install PyYAML
@@ -51,6 +52,20 @@ def load_config(path: Path) -> dict:
51
52
  sys.exit(1)
52
53
 
53
54
 
55
+ def escape_tag(value: str) -> str:
56
+ """
57
+ Escape a tag key or value for InfluxDB line protocol.
58
+
59
+ :param value: The raw tag key or value
60
+ :type value: str
61
+ :returns: The escaped string
62
+ :rtype: str
63
+ """
64
+ for char in ("\\", ",", "=", " "):
65
+ value = value.replace(char, f"\\{char}")
66
+ return value
67
+
68
+
54
69
  def gather_data(config: dict) -> list:
55
70
  scan_results = asyncio.run(ble_coro(config))
56
71
 
@@ -65,26 +80,46 @@ def gather_data(config: dict) -> list:
65
80
  else:
66
81
  macs_seen.add(scan_result["mac"])
67
82
  sensor = config["sensors"][scan_result["mac"]]
83
+ tags = {
84
+ "location": sensor["location"],
85
+ "domain": sensor["domain"],
86
+ "mac": scan_result["mac"],
87
+ }
88
+ tag_set = ",".join(
89
+ f"{escape_tag(k)}={escape_tag(str(v))}" for k, v in tags.items()
90
+ )
68
91
  points.append(
69
- Point("environment")
70
- .tag("location", sensor["location"])
71
- .tag("domain", sensor["domain"])
72
- .tag("mac", scan_result["mac"])
73
- .field("temperature", scan_result["temperature"])
92
+ f"environment,{tag_set} temperature={float(scan_result['temperature'])}"
74
93
  )
75
94
  return points
76
95
 
77
96
 
78
97
  def emit_data(config: dict, points: list) -> None:
79
- client = InfluxDBClient3(
80
- host=config["influxdb"]["url"],
81
- token=config["influxdb"]["token"],
82
- database=config["influxdb"]["database"],
98
+ """
99
+ Write line protocol points to InfluxDB 3 via the /api/v3/write_lp endpoint.
100
+
101
+ :param config: The loaded configuration
102
+ :type config: dict
103
+ :param points: Line protocol strings to write
104
+ :type points: list
105
+ :returns: None
106
+ :rtype: None
107
+ """
108
+ if not points:
109
+ return
110
+ query = urllib.parse.urlencode({"db": config["influxdb"]["database"]})
111
+ request = urllib.request.Request(
112
+ f"{config['influxdb']['url'].rstrip('/')}/api/v3/write_lp?{query}",
113
+ data="\n".join(points).encode("utf-8"),
114
+ headers={
115
+ "Authorization": f"Bearer {config['influxdb']['token']}",
116
+ "Content-Type": "text/plain; charset=utf-8",
117
+ },
118
+ method="POST",
83
119
  )
84
- try:
85
- client.write(record=points)
86
- finally:
87
- client.close()
120
+ # Raises urllib.error.HTTPError on a non-2xx response
121
+ with urllib.request.urlopen(request, timeout=30):
122
+ pass
88
123
 
89
124
 
90
125
  async def ble_coro(config):
@@ -136,7 +171,9 @@ async def ble_coro(config):
136
171
  timeout=timeout,
137
172
  )
138
173
  if not done:
139
- print(f"Scan timed out after {timeout}s — returning {len(results)} result(s)")
174
+ print(
175
+ f"Scan timed out after {timeout}s — returning {len(results)} result(s)"
176
+ )
140
177
  # Exiting the `async with` block here always runs scanner cleanup
141
178
  # synchronously and correctly, regardless of whether we timed out.
142
179
  except BleakDBusError as e: