safraeli commited on
Commit
16416cd
·
verified ·
1 Parent(s): 84b05b8

Fix TB timeseries fallback

Browse files
Files changed (1) hide show
  1. backend/api/routes/sensors.py +27 -28
backend/api/routes/sensors.py CHANGED
@@ -100,19 +100,36 @@ async def soil_moisture_history(
100
  return []
101
 
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  @router.get("/air-leaf-delta")
104
  async def air_leaf_delta(
105
  hours: int = Query(168, ge=1, le=8760, description="Hours of history"),
106
  ):
107
  """Hourly air-leaf temperature delta from ThingsBoard (Air2 under panels)."""
108
  try:
109
- from datetime import datetime, timezone, timedelta
110
- from src.data.thingsboard_client import ThingsBoardClient
111
- client = ThingsBoardClient()
112
- end = datetime.now(tz=timezone.utc)
113
- start = end - timedelta(hours=hours)
114
- df = client.get_timeseries("Air2", ["airLeafDeltaT"], start=start, end=end,
115
- interval_ms=3_600_000, agg="AVG", limit=2000)
116
  if df.empty:
117
  return []
118
  return [{"timestamp": ts.isoformat(), "value": round(float(row["airLeafDeltaT"]), 2)}
@@ -128,13 +145,7 @@ async def temp_humidity(
128
  ):
129
  """Hourly temperature + humidity from ThingsBoard (Air2 under panels)."""
130
  try:
131
- from datetime import datetime, timezone, timedelta
132
- from src.data.thingsboard_client import ThingsBoardClient
133
- client = ThingsBoardClient()
134
- end = datetime.now(tz=timezone.utc)
135
- start = end - timedelta(hours=hours)
136
- df = client.get_timeseries("Air2", ["airTemperature", "airHumidity"], start=start, end=end,
137
- interval_ms=3_600_000, agg="AVG", limit=2000)
138
  if df.empty:
139
  return []
140
  rows = []
@@ -157,15 +168,9 @@ async def ndvi_history(
157
  ):
158
  """Hourly NDVI from ThingsBoard — treatment (Air2) and reference (Air1)."""
159
  try:
160
- from datetime import datetime, timezone, timedelta
161
- from src.data.thingsboard_client import ThingsBoardClient
162
- client = ThingsBoardClient()
163
- end = datetime.now(tz=timezone.utc)
164
- start = end - timedelta(hours=hours)
165
  rows = []
166
  for device, label in [("Air2", "treatment"), ("Air1", "ambient")]:
167
- df = client.get_timeseries(device, ["NDVI"], start=start, end=end,
168
- interval_ms=3_600_000, agg="AVG", limit=2000)
169
  if not df.empty and "NDVI" in df.columns:
170
  for ts, row in df.iterrows():
171
  v = row.get("NDVI")
@@ -183,13 +188,7 @@ async def vpd_history(
183
  ):
184
  """Hourly VPD from ThingsBoard (Air2 under panels)."""
185
  try:
186
- from datetime import datetime, timezone, timedelta
187
- from src.data.thingsboard_client import ThingsBoardClient
188
- client = ThingsBoardClient()
189
- end = datetime.now(tz=timezone.utc)
190
- start = end - timedelta(hours=hours)
191
- df = client.get_timeseries("Air2", ["VPD"], start=start, end=end,
192
- interval_ms=3_600_000, agg="AVG", limit=2000)
193
  if df.empty:
194
  return []
195
  return [{"timestamp": ts.isoformat(), "value": round(float(row["VPD"]), 2)}
 
100
  return []
101
 
102
 
103
+ def _tb_timeseries(device: str, keys: list, hours: int):
104
+ """Fetch TB time-series with fallback: try AVG aggregation first, then NONE."""
105
+ from datetime import datetime, timezone, timedelta
106
+ from src.data.thingsboard_client import ThingsBoardClient
107
+ client = ThingsBoardClient()
108
+ end = datetime.now(tz=timezone.utc)
109
+ start = end - timedelta(hours=hours)
110
+
111
+ # Try aggregated first
112
+ df = client.get_timeseries(device, keys, start=start, end=end,
113
+ interval_ms=3_600_000, agg="AVG", limit=2000)
114
+ if not df.empty:
115
+ return df
116
+
117
+ # Fallback: raw data, resample locally
118
+ import pandas as pd
119
+ df = client.get_timeseries(device, keys, start=start, end=end,
120
+ interval_ms=0, agg="NONE", limit=10000)
121
+ if df.empty:
122
+ return df
123
+ return df.resample("1h").mean(numeric_only=True).dropna(how="all")
124
+
125
+
126
  @router.get("/air-leaf-delta")
127
  async def air_leaf_delta(
128
  hours: int = Query(168, ge=1, le=8760, description="Hours of history"),
129
  ):
130
  """Hourly air-leaf temperature delta from ThingsBoard (Air2 under panels)."""
131
  try:
132
+ df = _tb_timeseries("Air2", ["airLeafDeltaT"], hours)
 
 
 
 
 
 
133
  if df.empty:
134
  return []
135
  return [{"timestamp": ts.isoformat(), "value": round(float(row["airLeafDeltaT"]), 2)}
 
145
  ):
146
  """Hourly temperature + humidity from ThingsBoard (Air2 under panels)."""
147
  try:
148
+ df = _tb_timeseries("Air2", ["airTemperature", "airHumidity"], hours)
 
 
 
 
 
 
149
  if df.empty:
150
  return []
151
  rows = []
 
168
  ):
169
  """Hourly NDVI from ThingsBoard — treatment (Air2) and reference (Air1)."""
170
  try:
 
 
 
 
 
171
  rows = []
172
  for device, label in [("Air2", "treatment"), ("Air1", "ambient")]:
173
+ df = _tb_timeseries(device, ["NDVI"], hours)
 
174
  if not df.empty and "NDVI" in df.columns:
175
  for ts, row in df.iterrows():
176
  v = row.get("NDVI")
 
188
  ):
189
  """Hourly VPD from ThingsBoard (Air2 under panels)."""
190
  try:
191
+ df = _tb_timeseries("Air2", ["VPD"], hours)
 
 
 
 
 
 
192
  if df.empty:
193
  return []
194
  return [{"timestamp": ts.isoformat(), "value": round(float(row["VPD"]), 2)}