initial commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import os
|
||||
import time
|
||||
import math
|
||||
import requests
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
SIDECAR_URL = os.getenv("SIDECAR_URL", "http://localhost:80")
|
||||
|
||||
class WriteBatch:
|
||||
def __init__(self):
|
||||
self.payload = []
|
||||
|
||||
def add(self, signal_id, value, name=""):
|
||||
self.payload.append({
|
||||
"id": int(signal_id),
|
||||
"value": float(value),
|
||||
"name": str(name)
|
||||
})
|
||||
|
||||
class Plant:
|
||||
def __init__(self):
|
||||
self.state = {}
|
||||
self.instants = {}
|
||||
self.signals = []
|
||||
|
||||
def _parse(self, data):
|
||||
self.signals = data
|
||||
self.state = {}
|
||||
self.instants = {}
|
||||
for item in data:
|
||||
val = item.get("value", math.nan)
|
||||
instant = item.get("instant", 0)
|
||||
self.state[item["id"]] = val
|
||||
self.instants[item["id"]] = instant
|
||||
if item.get("name"):
|
||||
self.state[item["name"]] = val
|
||||
self.instants[item["name"]] = instant
|
||||
|
||||
def read_all(self):
|
||||
try:
|
||||
res = requests.get(f"{SIDECAR_URL}/api/read/", timeout=2)
|
||||
res.raise_for_status()
|
||||
self._parse(res.json().get("data", []))
|
||||
return self.state
|
||||
except Exception as e:
|
||||
print(f"Error reading state: {e}")
|
||||
return {}
|
||||
|
||||
def read_sync(self, interval_ms, offset_ms):
|
||||
try:
|
||||
timeout_sec = (interval_ms / 1000.0) + 2.0
|
||||
res = requests.get(f"{SIDECAR_URL}/api/read/{interval_ms}/{offset_ms}/", timeout=timeout_sec)
|
||||
res.raise_for_status()
|
||||
self._parse(res.json().get("data", []))
|
||||
return self.state
|
||||
except Exception as e:
|
||||
print(f"Error reading state: {e}")
|
||||
return {}
|
||||
|
||||
def new_write_batch(self):
|
||||
return WriteBatch()
|
||||
|
||||
def send(self, batch):
|
||||
if not batch.payload:
|
||||
return
|
||||
try:
|
||||
res = requests.post(f"{SIDECAR_URL}/api/write/", json=batch.payload, timeout=2)
|
||||
res.raise_for_status()
|
||||
except Exception as e:
|
||||
print(f"Error sending batch: {e}")
|
||||
|
||||
def run(logic_func, interval_ms=1000, offset_ms=200):
|
||||
print(f"Connected to: {SIDECAR_URL} (Sync: {interval_ms}ms, Offset: {offset_ms}ms)")
|
||||
plant = Plant()
|
||||
while True:
|
||||
try:
|
||||
if not plant.read_sync(interval_ms, offset_ms):
|
||||
time.sleep(1.0)
|
||||
continue
|
||||
logic_func(plant)
|
||||
except Exception as e:
|
||||
print(f"Logic Error: {e}")
|
||||
time.sleep(1.0)
|
||||
@@ -0,0 +1,79 @@
|
||||
import os
|
||||
import requests
|
||||
|
||||
try:
|
||||
from dotenv import load_dotenv
|
||||
load_dotenv()
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
DB_URL = os.getenv("DB_CONTROLLER_URL", "http://127.0.0.1:13213")
|
||||
|
||||
class Database:
|
||||
def __init__(self):
|
||||
self.base_url = f"{DB_URL}/api"
|
||||
|
||||
def get_row(self, table, row_id):
|
||||
"""GET /api/db/:table/:id/"""
|
||||
try:
|
||||
res = requests.get(f"{self.base_url}/db/{table}/{row_id}/")
|
||||
res.raise_for_status()
|
||||
return res.json().get("data")
|
||||
except Exception as e:
|
||||
print(f"DB Read Error: {e}")
|
||||
return None
|
||||
|
||||
def insert(self, table, data):
|
||||
"""POST /api/db/:table/"""
|
||||
try:
|
||||
res = requests.post(f"{self.base_url}/db/{table}/", json=data)
|
||||
res.raise_for_status()
|
||||
return res.json().get("data") # Returns {'id': lastID}
|
||||
except Exception as e:
|
||||
print(f"DB Insert Error: {e}")
|
||||
return None
|
||||
|
||||
def query(self, table, filters=None, order_by=None, limit=100):
|
||||
"""POST /api/db-query/:table/"""
|
||||
payload = {
|
||||
"filters": filters or [],
|
||||
"orderBy": order_by or [],
|
||||
"limit": limit
|
||||
}
|
||||
try:
|
||||
res = requests.post(f"{self.base_url}/db-query/{table}/", json=payload)
|
||||
res.raise_for_status()
|
||||
return res.json().get("data")
|
||||
except Exception as e:
|
||||
print(f"DB Query Error: {e}")
|
||||
return []
|
||||
|
||||
def update(self, table, row_id, data):
|
||||
"""PUT /api/db/:table/:id/"""
|
||||
try:
|
||||
res = requests.put(f"{self.base_url}/db/{table}/{row_id}/", json=data)
|
||||
res.raise_for_status()
|
||||
return True
|
||||
except Exception as e:
|
||||
print(f"DB Update Error: {e}")
|
||||
return False
|
||||
|
||||
def list_tables(self):
|
||||
"""GET /api/db-meta/tables"""
|
||||
try:
|
||||
res = requests.get(f"{self.base_url}/db-meta/tables")
|
||||
res.raise_for_status()
|
||||
return res.json().get("data")
|
||||
except Exception as e:
|
||||
print(f"DB List Tables Error: {e}")
|
||||
return []
|
||||
|
||||
def list_columns(self, table):
|
||||
"""GET /api/db-meta/tables/:table/columns"""
|
||||
try:
|
||||
res = requests.get(f"{self.base_url}/db-meta/tables/{table}/columns")
|
||||
res.raise_for_status()
|
||||
return res.json().get("data")
|
||||
except Exception as e:
|
||||
print(f"DB List Columns Error: {e}")
|
||||
return []
|
||||
@@ -0,0 +1,14 @@
|
||||
import time
|
||||
|
||||
def now():
|
||||
"""Returns current time in Unix Milliseconds (standard JS/App format)"""
|
||||
return int(time.time() * 1000)
|
||||
|
||||
def now_sec():
|
||||
"""Returns current time in Unix Milliseconds, but floored to the second"""
|
||||
return (int(time.time()) * 1000)
|
||||
|
||||
# If you need to convert a JS-style milli back to a Python datetime for local logging
|
||||
def to_datetime(unix_milli):
|
||||
from datetime import datetime
|
||||
return datetime.fromtimestamp(unix_milli / 1000.0)
|
||||
Reference in New Issue
Block a user