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