From 314480976aef53b1fa39e43d75a09a74919b46f7 Mon Sep 17 00:00:00 2001 From: Eric F Date: Mon, 8 Jun 2026 23:14:23 -0400 Subject: [PATCH] Fix simulator - working ingestion with America/Martinique timezone --- .../cariflex_simulator.cpython-313.pyc | Bin 0 -> 6453 bytes scripts/cariflex_simulator.py | 131 ++++++------------ scripts/start_simulator.sh | 6 + 3 files changed, 52 insertions(+), 85 deletions(-) create mode 100644 scripts/__pycache__/cariflex_simulator.cpython-313.pyc create mode 100755 scripts/start_simulator.sh diff --git a/scripts/__pycache__/cariflex_simulator.cpython-313.pyc b/scripts/__pycache__/cariflex_simulator.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1f0fd988ff36bbc6a56104ce259d4ff1a328bc0 GIT binary patch literal 6453 zcmb_AX>c3Yd2biHxDOrxFHz)@IwAA0#K?-ME7So>;w52$*eWTbOJE7Y!lk!>M8Zed zCY=G}OhhSGMWvb=?f3`P>4A1S6V~GyD~{vPzX}LSg={&EJoO*^qpfD*asTvt3oZ!L zbX|AyNPPR=+wXnHd*Ai;sl{SM(0=s2Juf|HL+C%rKyBLf&eP*GLbnl*Fybkm9-=U% zJZVfTPYu>6PX;r}lf|s^)MBmj)L|VwHADLIdaOThz=rciY~;$cOxQG`bvLOjH=dn{ zXAV;3F^48BFlN;;jj(lsa<^?@tG!M%VO6nk4NsH5gCIR=z)_29Cu(>d3nN?yJ-yPa zpD?-Y3d$D%a5PkC*`Gz&G0^~XM&6`StVd^SfKnrG<}IM1mACaU6Ar#+qOlt&?SbD& z9YQAH{FN(f`8vLyx38~se1nw@3eU#%l}+DZWi#+>;kT`?Z2j^|etQeTO?(@`X1*O@ z%fvRG>wf_uL66WxOD8(GzEd0u(m}cdb)miMGXXfWDVjs=pf!g^-#(^kM^luuBX#84^)QPzfn(HIs}b-js5ymu<%^J6g}^}Hm- zqN(lEi9}rL@9p)k3)B+`1w#oOniPAcu*`}PArzMNaY2%<$8aE3HxLnV$S?Gc2sjan zhOQ>X5-5pECIB)Wzb4aHo-YwgaxyZLn2n1vlZ=KEvL+IW0uW|OWOHQQq>xC6cvjY2 zd49S?+^!TL-~f4P6tDUG(*h2PxYR&qkCIs}%w9VXEP-dD(hvbI0RDA@hAu)@_-Wwx z^gV#Lkr&*Gh!Ul}VEW3Dy^0X8@lq0fjPCD;BLuhR8KnoKF*vHRL*qmrrSa@|g}R$j zXE&am$P2FA4boTPsexhx4RwPMytW&*NOd9AX~rm?jcUdXDsnY%kX~_4uZFB2S3(oP zbDLG{jVB2Ryk4bB98T?n+pg=d6TvPRm0gGdy)AeGM-$nvak9lqQ)M7dU8Un6bT5c@ zMB@L0h810^HB|N6q^VWW6vNKjHl25ka^5ZL=iOMv7XsMk20II3N#!xt@U_@1U$0{S z!A{n$Qmoc{lfDi`UvMIx-K4KZ(HC}Ev2U7h7^~+SH{mpG!m)s5Hba02*Lo`+KF`%zffnMoWR@Q1qK^ICBmcRAb{+CiNqJDLE$Vj z5g{=xYa|G5bUY-pIF^hCWGxn=fmlRlgF;f06j@{)1i`5ojyPFaySAifjt<4BYD_fE$mVlN4{mDt=X`Ee+okSY^CNzEQT@mbj#6r&=BRN%WN zgp(pZ1jL9M(jr8(IaJh}(yn>a+(1#MPoMt&Z1Fn-4?MrLt++q1y-~k#@gDQ0{-^rP z&ZXMF+WWVGe+b?W<~t59)A^46Ler5)wMTQ_@20h@Hv1d=V(sFo414$dQbWGA_n&wF ztm~h;majh8Q8?hrx4H_B!Ij#AZ78Q7DjJOG(CcmGHT8?$yDe|=OZ7|M`z=}ba_2jV zcW2(7S+VCXT>P-@Cm%LUG zujdb5FYKBrIA(J%zf!Qhn$y2ZIE4#_mST5LcIV&umOKC6_eR5=wp(o(O@@C|>wJIr zuX^6=$z62kJTDYZUiyFNG5z}XqN8DP=j|6W9e@7fJYK?C&#!w=EW7`$_r(3W2ktbp zm71P+T<;FQJ-kx8GEg`=nm;&N*fmygT*$fkg3XiDdx|FWQ#c^xucRCp5Ia?p*k8l! zZPW&7%w7GSEP%EVj;)a9`bc%BIZQ_>FSS*wf+Tkx(jCwVvg4H$wSNh1RRNn$eWDHyjIwqL@SpCnf7h=@m;RN-HpSrJP4Y(Rea3 z{^Ie=`}`7~@+D$d#Hcb<9Q9b|-tiYZFF)h##3U)p)U1=iI_P0?JhE|PjjYFFM2t*| z*aKxBLn=ktCWOPW>pm#yLRj=CBn*WNk_`btnx2daI3Tl%Y$+SZ4HF?b5#t!{=k8N7 zI~7h!(@u-535p3>=Nj>y9pgQ+NlFNbq~!C*0-{V~C?F+K!2W5d=fs(W%*3HgmGyvq zW@O;puxx_fg#n&_e$0IuVjjf6xU5OyuxvOp;}_!zC|PATjziG|l!UtVB37oLxP<5l zR4Gv+^#lYx4nIeg#HAfzEK(me@q9+BTC2V^e}WRS7~5rYgrWD z6z__8+m6S!Bbn=2;b-DMiupZ9a{42mt(xpl5zRVQ^_B%&hFX+z)*VaVdZ>REqQrl% zvGC?|X$L6wr+ZFzqrce;;OF%N&G2}y+jz>VdGCjyfmlTf zf=w;TfMhKEv>UtX-o6P5hUzU5?#Vw!C<(Pnd}h2|#e3lgmFQ~lYQ{U%d2+)(Opz;w zo7l^yrqYZWl`OGq(`y)3TLr{U9pnm2ALBLjQeGp(I6ZG8M#0zcwLL7keIM3DOql3u*CEAb+!$1-Q+t1=#9k0B-Lys5Hh&%ut%UOYLnuA-C13=gFZ#YQ%|1 z9#9PuK^}lrQS%l$fsIs2Qr4;2Yp#}G$r0uO^T?;DoG(cKGuU0AIAE^I7;U4ehOIsT z9Opdv6iAygaU3s3r5Kj_xl|j+dDgG;{oI$Y-!6i1#_b++_jBjqrX3Q(oD%W5DY&|e zfsRy@68VE-fP?5SCH;Q*jxd!Bhi8>S8k5XTk``RhlL=9R&jdm|)O)SZ_iV3J7NR%B z_A0rCx!^fCg30Yrc94%1Wg$;P8gh&9B|u6*d8<`&nk2K3MKI)vKoUw)$N|c-ayh?~ zaHM61e1TBXm6OKAxJn-aP;wxKgFz{Sx(!@P*Uz2xcrI`$8g|6Yap&OUfkKu`vE0~D z7nicG>&xvWrS&nHaylFFMMBU8K-PrCsI249jPhe{p5#$QUJ0hkUsXVEsI{kN%h`v- zSXmQ|U6(B*18&c`(Q_BQXMCPN!o*u3yCwYi0O_%zgcy;ON*j|TCL2OhjMVu;0uR9$ z4-#;JykSUD0J{KUG3D)nR6q-Y;j3H<4eCtrgnKO1}Pd{W1 z!%TYUp61@*UzitO%Nchs1s*be3fjKxw;nRz{@B{^*xL5c+E%b~bAv@k%iQ1(Mn5*y zEHvIYK7SmtUe4N+4LsBzDeA3cnQ`Y5klp{JrgrXJ(P&+@x851PHT>50g1t9wSgmWh z({-!s-pre?+KfjErTT2UxadcO@kaAYlw1q=mqLYz5ULy zo5wQe3-vufb@A%W;ah`G>`(*T99nP{8@Fd_fAaEb)Ao#E$+@&GJGeaX?#RE4ET71= z4dwXfA2q%3i3T<8_{4$Qd)7LUp>E;gycINu^1!@!X>llnm-Z|*XLl`Yvop)DtprxS zo8vt>t2cL9c&MLT)the^e`s7d@FVM|2a(D4*?;Xu_U%uRhNxK6u-I|aw4g24H!oiN z$&poi^WwQoC^Md=v-`6<8W32JP&x>@4(Uz0XIi#piRj$~vDf5cB(d_%f`+lLYh-K*BA434pA>F5qY= z8kF!^GDkc}af!0aF!9+$O14gg!eH?#rp(0R;FZ*r%!FeCT%5~aCKZRp!-T*H0aFAB z0N{cxM1!JCg~}eM6pF-_iKtN_BKmyy5hjLRHg^5dNGy;Hi^uVwz#N!5l8ypg(@+%k z5jy`{bm+12UqFX`iw@+`fqzG)CrJMoH9ka*i~2{X<0BSqx9t(zp4nft)ZV!C!%GWS zU!RzB{a%B#+?p1d_RZ;vrrL!)^C#x?MRVOkf8N|SXDZg%?^teGa%~3+HGOlICr0y} z?l%T&`szaGk6Yma-o9hWv)u7uAm8Ac8%&>EsGWCxe+(?d*zi#`*52%{2lPr`zG3Wt z!+Iv`dC;+P@@ug6WF5]*csrf_token[^>]*value="([^"]+)"', r.text) + if not match: + return False + r = session.post(f"{FM_HOST}/login", data={"email": FM_EMAIL, "password": FM_PASSWORD, "csrf_token": match.group(1), "remember": "y"}, allow_redirects=True, timeout=10) + return "dashboard" in r.url or "login" not in r.url + except Exception as e: + print(f" Login error: {e}", flush=True) + return False + def main(): print(f"Cariflex Simulator -> {FM_HOST}", flush=True) print(f" Sensors: {len(SENSORS)}", flush=True) + print(f" Timezone: America/Martinique", flush=True) - # Create session with CSRF token handling session = requests.Session() - session.verify = False # Self-signed cert + session.verify = False - # Get login page to extract CSRF token - login_url = f"{FM_HOST}/login" - r = session.get(login_url) - print(f" Login page: {r.status_code}", flush=True) + if not login(session): + print(" ERROR: Initial login failed!", flush=True) + return + print(" Logged in successfully", flush=True) - # Extract CSRF token - from html.parser import HTMLParser - class CSRFParser(HTMLParser): - def __init__(self): - super().__init__() - self.token = None - def handle_starttag(self, tag, attrs): - if tag == "input": - attrs = dict(attrs) - if attrs.get("name") == "csrf_token": - self.token = attrs.get("value") - - parser = CSRFParser() - parser.feed(r.text) - csrf_token = parser.token - print(f" CSRF token: {csrf_token[:20] if csrf_token else 'NOT FOUND'}...", flush=True) - - # Login - r = session.post(login_url, data={ - "email": FM_EMAIL, - "password": FM_PASSWORD, - "csrf_token": csrf_token, - "remember": "y", - }, allow_redirects=True) - print(f" Login: {r.status_code} (url: {r.url})", flush=True) - - # Check if logged in - if "dashboard" in r.url or "login" not in r.url: - print(f" Logged in successfully!", flush=True) - else: - print(f" WARNING: May not be logged in (url: {r.url})", flush=True) - - # Post sensor data iteration = 0 while True: - now = datetime.now(timezone.utc) - hour = now.hour - + now_local = datetime.now(MARTINIQUE_TZ) + now_utc = datetime.now(timezone.utc) + hour = now_local.hour success = 0 failed = 0 for sensor_id, cfg in SENSORS.items(): value = generate_value(cfg, hour) - start = (now - timedelta(minutes=5)).isoformat() - + start = (now_utc - timedelta(minutes=5)).isoformat() try: - r = session.post( - f"{FM_HOST}/api/v3_0/sensors/{sensor_id}/data", - json={ - "values": [value], - "start": start, - "duration": "PT5M", - "unit": cfg["unit"], - "type": "PostSensorDataRequest", - }, - timeout=30, - ) + r = session.post(f"{FM_HOST}/api/v3_0/sensors/{sensor_id}/data", + json={"values": [value], "start": start, "duration": "PT5M", "unit": cfg["unit"], "type": "PostSensorDataRequest"}, timeout=30) if r.status_code in [200, 201]: success += 1 else: failed += 1 if failed <= 3: - print(f" Sensor {sensor_id}: HTTP {r.status_code} - {r.text[:100]}", flush=True) + print(f" Sensor {sensor_id}: HTTP {r.status_code}", flush=True) except Exception as e: failed += 1 if failed <= 3: @@ -130,8 +93,6 @@ def main(): iteration += 1 print(f" Iteration {iteration}: {success} OK, {failed} failed (hour={hour})", flush=True) - - import time time.sleep(30) if __name__ == "__main__": diff --git a/scripts/start_simulator.sh b/scripts/start_simulator.sh new file mode 100755 index 0000000..84a0428 --- /dev/null +++ b/scripts/start_simulator.sh @@ -0,0 +1,6 @@ +#!/bin/bash +# Cariflex Simulator Launcher +export FM_PASS="Digitribe972" +cd /home/eric/cariflex +nohup python3 -u scripts/cariflex_simulator.py > /tmp/simulator.log 2>&1 & +echo "Simulator started with PID $!"