From 009131099a6660639c6690e6cf60406fe9fc9748 Mon Sep 17 00:00:00 2001 From: devmatrix Date: Fri, 20 Feb 2026 17:24:20 +0000 Subject: [PATCH] Fix max temp display - properly classify HTTP sensor CPU temps --- __pycache__/fan_controller.cpython-312.pyc | Bin 35644 -> 36174 bytes fan_controller.py | 41 ++- server.log | 353 +-------------------- 3 files changed, 46 insertions(+), 348 deletions(-) diff --git a/__pycache__/fan_controller.cpython-312.pyc b/__pycache__/fan_controller.cpython-312.pyc index 01117a436ba6c81df82901689c14f843320ad499..ea1e65d63263b99dd9b4eb2acd81678e40abccb3 100644 GIT binary patch delta 4809 zcmZ`-33OD|8Gd)RO!j3a2}2SxAtX3~kPVQ8B@79xB%vW}Avg|sk7RH%Gu-zAWSo!) zia|L??DdqmR8WhAgBIve50z4=S_Nq{xsXGE+bdgxmF7 zmxvKCD9B`MgJ@>`@!5JmPO!krre;U6@d>GMkq^dtN z)#LE)gvHCFL#7vmpX)>BP=pvG#=ai67aYfDFVWsa*haRR4MIq_P{-Ecob;J?R<|O8fRf+2sDWf_N4w{{!JD^CkOf}A|t*xmIMz}n_ zK&w)w8WgD|@HN|#SX>yVM#%xMNAY@mlB^nKg?a+OQruLL*Ljp?HNqo{o+gi?8e0Pa ziL!4K=R~McbA6(;o)soN-f=%T-YHy2Na`~7rP{h;E?9@3vF7wzb52`FUl(kV8C{iq zmelQK&y=w#U6t2NLV~rsa!1W`H9Zv{r5EmBc+7CXb-eCW?ZOjFK6IUMeN^>epCw~w zU9ZK_({!lrX#H>M4>$CVo7S+#KT$|X?uz-x4-rDf=+~o8rImaykmL+?SbD!6 z-nV26?AP0qoY|Fj-MjYq$`a$d#iX)?owL|%7#}_SUC)JuZWlx%>byd`K149pbnOOq zK6k{}b|WO1ajih3L_=Oo_pFdjup+G^U(pwha=98zw--@l-X4@k5*h&M}LL10zWT zBMG8qfMXrtB)6qFQiItQUbifJR<+q>$tSZHtts<(9#yO6Mn9D>WmH39VPR3w?2+C1 zNU4U#Kx;8aq(LeegV-SF-Pa(FanLeY)Ym2ecFH=sBeK!o67b6&MN$o3e

>7ON4B z&7OcPL5BI2W{EnCs*Xx@DQKxCS#s0HW||8hGzY+8rW24(Kv;>O0H{$ucZ=lm`qxQR zjY4xnG6K zo#p%Iowk*C&HFgs_DR}^?%~ z&+DDK7>xDBTDApyW3wRBgS|PWeU|h-=u!Ra)7Xt~ z01iT5gx4ND52YF*w>CCPvP|azlO44?$$N}sT_(HO*I5P0C`q>}2^Pmy(k# ze$+_TGxCqgzd+`$A$Sd`*VvZq98-@belWY9oDRp2T1rfsENjUrh~}m>t890U-SjdF z&treesUT;=iMdyF(Ot;FGNskb1k?AjR5};{fdJn!~~t6cp)nB)q90QJ#iIl-ot z<&aOASauvRfAV-TDZFy>J9_xYEgu^l3(gNDKU-1mWLKOS>~MKB35DM;{|8A*fnkSH z3(;^CO=G=I8%be1%F|;+NeZ}H1EO1zy26$jGj*hzEvt0S`xNF^O#wHRe9(4V9u_^6 zT2R>vpc=&1mH@qDUR>35gc$%1gEmTt7pavq>scl^mdvwlZ@+vzrXGCT(j5>7mbJY9-pxR-gxK7Qd zJa%i&1c+ea+zMzx%G?9Gq6;W_5nz@!-CX>>gwO{79^ccWHnYX^%S-tRr=S#uj1rvT z6{MU9yw%J=DgI;H^W({D;al^~x9l&4)PXw{xXx8scWiQnvkhjA7Y8L6p=ge4J>ei!)2}5?cbGK(fO&STH zn(CUVGB})CY z%nG-L&v+9)fx|NaWD@}N5qPwOoW`6=Iy+k*1FiY1`uFwZUu^$_ z!^(ex3iHqur&{3C5ve66PbGpwykGEu&q8tD8xxUgU=gkdOtU~{AjW=I0%@#6^^)%;ZT}A8PqV<>o>vgb~_EtTx-riq9|HHm(&T8Os#BN3Z zj_^+ezGeSLDhEI{Hn!5W61|R$D+m~I`VBzP$W6ilG8ET4!@<0s(b0=gIE;|NUh<@q zgY2-U$n-rjs@V6QSHBx`8PlPz~nyg~6Yx2kq z){>M;maqkDiikJ7am`plZiM&I5<d65D?McH0gwrr;nuC#6~CQQG>Pq|nks;U?KTT7-8N@{Pe|2)TwMx+!BH6H zI56Xa^VuZ_BuRWS+`0A@l6Mw_@mPiDLOD+yMcD zP>8K)n?YUeq7nJHLfm!UR@4OEeq{G53481+ zPt#zWs!(ni+tpbKz57Zh(UH&C)r}ceezF?9ezyoev+;nHX)MdwG?F|Dr^y(&&3ZRc zqO$Xwk~=zZ78}AuggCUAiNMc5zSa1vn|9(TKMr{7FGt=CglPyy9ObtcY&R6khNdA8 z8=ZF1TY|jB2$(>09YPy{BZ)qOWIMt}ghvsunC`gioWoCq3E@{Cn@q?#cK-2UaA!F` zH<>-OFp{NgUK{%)>Y)r2;iv4m&FRLi!0BUeZJtJsu$!Bw!`-OtiJ5s@fa{n@`NA36 zRSV0$SfO_DX zW02N+6n+s<4XrZ#P}B$3iP}DF23`35s!*?X{`2O}V?OYj&R5pM^H$R#_~Uea`0N%p`7c@>=ym`A delta 4287 zcmZu!32>BE68_&@xhBcvViJ;&$uWdU2uZjJM+ga*3E_&!ot@46gh_^(;r;(4BqSuF zXi&;U+ZA+0NLebB)GqjYqHL+`u3H|fh_c~dT&UF*MWqrEQFhhsev<^jovM6)zkc2Q z`gQl~_wu(#46i(7hPs>Tkf zLY>VXXK5ZIkwjOA*%Ofly$yEQZA&vm4v~@YrEPgaREOnv(mrEHWJiQ2+7olw3cUqM z`JbAk4#RROS5i~SZTjU&+{mO=(ynh>r7gx)QY&-C!XpXJjBBi{-QaMvN7Q@$!H`;} zn^bvI@N)y|aQGr&{PSGS`^#WPPgTD~ zvL*kfb7$w?FzxCm*2Pd4$D&B4Fv!%lBq&nj%#}v4d zG;_ff$&!}dpN-b~CrY-I9_x4CL`WH!yZ{-XI)^9s%EucY2K;)?sXsc#_A^!7xiEkCDEdwV6ETL5^jR6VVpw zi4xKbsc525K4zF>6`V*QYsHwV;>GC#!l3iQ}z;*%&ro8)?5pjGCI2^kLj@liCr3I-DG z5M@uE&T*)0M!=k;r0rRK|7uv<6Wte+uzU5%n5@3|#ND2qTlY2`sC&4%&z{+rki6G) zfBFIA0kt;<_Sq*y-TG?N$(c*~lG5M{`!03|Y)RcP{xk#^f;|WJ+zV_U{FGaqLUO#Dpn~8bf;~`~w~`%$NAoVFJW7mx z!|)hUkHLPY({g~wJ@BS;HG3UJbF}%RCo@Y}9`495juEEAR^fQQ!?KqY9)^$eE7_Y` z{+Nq~m@eXoqgVqOh0_a{;Mf%_eCJDP?lyvD1S=7A16Gnnk=?vuBXk#*xK`6lJOV0- zf)Pv1CvFwNIs}~s`Fc20sIt>q?bxfvu}6q$mVI7D)lC~hKA&#f;P&fA9^Aw=(z@=| zbFjH&M9h=Ke2QQ{JWx{5CH5uUqguVmNB%tVULbgpU^Ib~Ksf6_$`yB$v*?D~uLy7X zF%n%*Ad3HGqFy1$A;?C6>7`bT_=3_!h5Kq@<7xwmE6=w5iZEDVt@%u1Sko z3!I&lIklC$lV6;64}$limi zW#udcQ>M>nPe9jnCGsSS95V1~xHkP(b^?~naI(|TGUKm^R|zK5N#_RD8$M<8abt4#z){1d|YS)~w@h4pbCDT2%~d)tpsx4Xg&5 z=T+Qt8dugWK{uEEs&3xY?D29QLyA^XG5e&7Gu{LA=pO4Q8r4-1S_@fmat!We>o+ zw~Wdvz@f{)&yw&*2(>N?r>%xv%K>ZkBsK=-R99k0xvTo9p>%lBdEr$Tk|r(9-$Ovh z+ll^pkJ?yUK22_T;w2Nr} z!i4bY`U2xwZv*TZnyf1WPb)|?+x zN5W4Nq`;Bp40agaX)d)~B*t7Y`Q~ABtoBW{)X>H*!A@T`E64baW$9X<&ue7W+MM78 z#s;9@o(!{iT5L6GW*}ftj)8}-WWR#rJkKKdm*4`=N?S=HbdBj|9tin8m_czEt07A% z7M9$j^^7ZM~tlh^nR)v0O!qxv^h`HzWGg|FOk? zDiRA2P*>7zqIoIq4Kj7&4c^9~gw3T$*x-fjRoLPGyPX-B4nN+RnJjK!voGNG;QwrN z2`k(T#XE9X8(uXT;NKCC@7HZRIC~!kcBFK*&`N0plL;(j)lMKTNfGX18j8n^xH!Zm zF@<<#1d|EOq$^%DvuIdOkS^>I&=KKO_PmyWs)+{(HZ#1pIK85Hh@hRIjergw&m)eKapKvqvz>~_*2Av~<7;pv_X^PR|f1K#eLg>U+powM=f zRI_t#!R^R(P3B_L_mIu!2}DVXxJCE^jg4M^BWLjP&ZoNChL+`G0THH=#3SpvQE5}c zuWyr^H@4{JAot=^$Ruy^s^XQPn?j1rbz`vA6OKVA>f*n5D))sS2gk{lXzSE=!?#in zQMm{%LyqXc+=h#ZHe6C7qH!&9#-@NL= 2: name = parts[0].strip() try: - value = float(parts[1].strip()) + value = float(parts[1].strip().split()[0]) # Handle "34.000" or "34.000 (high =" location = self._classify_sensor_name(name, current_chip) temps.append(TemperatureReading( name=f"{current_chip}/{name}", @@ -106,26 +107,42 @@ class HTTPSensorClient: status="ok", source="http" )) - except ValueError: + except (ValueError, IndexError): pass return temps def _classify_sensor_name(self, name: str, chip: str) -> str: """Classify sensor location from name.""" + import re name_lower = name.lower() - if "core" in name_lower: - if "0" in name or "1" in name: - return "cpu1" - elif "2" in name or "3" in name: + chip_lower = chip.lower() + + # Check chip name first for CPU identification + if "coretemp" in chip_lower: + # Extract CPU number from chip (coretemp-isa-0000 = cpu1, coretemp-isa-0001 = cpu2) + if "0001" in chip or "isa-0001" in chip_lower: return "cpu2" + return "cpu1" + + # Check sensor name for core temps + if "core" in name_lower: + # Try to determine which CPU based on core number + core_match = re.search(r'core\s*(\d+)', name_lower) + if core_match: + core_num = int(core_match.group(1)) + if core_num >= 6: + return "cpu2" + return "cpu1" return "cpu" elif "package" in name_lower: return "cpu" elif "tdie" in name_lower or "tctl" in name_lower: return "cpu" - elif "pcie" in name_lower or "nvme" in name_lower or "gpu" in name_lower: + elif "pcie" in name_lower or "nvme" in name_lower or "composite" in name_lower: return "pcie" + elif "loc1" in name_lower or "loc2" in name_lower: + return "chipset" return "other" def is_healthy(self) -> bool: diff --git a/server.log b/server.log index 60b66f6..1b4e7c8 100644 --- a/server.log +++ b/server.log @@ -1,345 +1,26 @@ -INFO: Started server process [25918] +INFO: Started server process [29754] INFO: Waiting for application startup. INFO: Application startup complete. INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit) -INFO: 192.168.5.30:64198 - "GET / HTTP/1.1" 200 OK -INFO: 192.168.5.30:64198 - "GET /api/status HTTP/1.1" 401 Unauthorized -INFO: 192.168.5.30:64198 - "GET /login HTTP/1.1" 200 OK +INFO: 192.168.5.30:55306 - "GET /api/status HTTP/1.1" 401 Unauthorized +INFO: 192.168.5.30:55306 - "GET /login HTTP/1.1" 200 OK +INFO: 192.168.5.30:54183 - "GET /login HTTP/1.1" 200 OK /home/devmatrix/projects/fan-controller-v2/web_server.py:149: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). self._sessions[token] = (username, datetime.utcnow() + timedelta(days=7)) -INFO: 127.0.0.1:33886 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 192.168.5.30:61387 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 192.168.5.30:61387 - "GET / HTTP/1.1" 200 OK +INFO: 127.0.0.1:36770 - "POST /api/auth/login HTTP/1.1" 200 OK /home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). if datetime.utcnow() > expiry: -2026-02-20 17:07:43,397 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json -INFO: 192.168.5.30:61387 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:61387 - "GET /favicon.ico HTTP/1.1" 200 OK -INFO: 127.0.0.1:44038 - "GET /api/curves HTTP/1.1" 200 OK -INFO: 192.168.5.30:61387 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:07:48,925 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -2026-02-20 17:07:49,084 - fan_controller - INFO - Connected to IPMI at 192.168.5.191 -INFO: 192.168.5.30:61387 - "POST /api/config/ipmi HTTP/1.1" 200 OK +2026-02-20 17:23:59,479 - fan_controller - INFO - Loaded config from /home/devmatrix/projects/fan-controller-v2/data/config.json +2026-02-20 17:23:59,481 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json +2026-02-20 17:23:59,638 - fan_controller - INFO - Connected to IPMI at 192.168.5.191 +2026-02-20 17:23:59,638 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888 +2026-02-20 17:23:59,639 - fan_controller - INFO - IPMI Controller service started +INFO: 127.0.0.1:36774 - "POST /api/control/auto HTTP/1.1" 200 OK +2026-02-20 17:23:59,796 - fan_controller - INFO - Manual fan control enabled +2026-02-20 17:24:04,639 - fan_controller - INFO - Fan 0xff speed set to 12% +2026-02-20 17:24:04,640 - fan_controller - INFO - All fans set to 12% (Temp 35.0°C) /home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). if datetime.utcnow() > expiry: -INFO: 192.168.5.30:61387 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:61387 - "GET /favicon.ico HTTP/1.1" 200 OK -INFO: 192.168.5.30:61387 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:61387 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:07:56,586 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -2026-02-20 17:07:56,769 - fan_controller - INFO - Manual fan control enabled -2026-02-20 17:07:56,924 - fan_controller - INFO - Connected to IPMI at 192.168.5.191 -2026-02-20 17:07:56,925 - fan_controller - INFO - HTTP sensor client initialized for http://192.168.5.200:8888 -2026-02-20 17:07:56,926 - fan_controller - INFO - IPMI Controller service started -INFO: 192.168.5.30:61387 - "POST /api/control/auto HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:61387 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:07:57,084 - fan_controller - INFO - Manual fan control enabled -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:61387 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -2026-02-20 17:08:01,333 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -2026-02-20 17:08:01,540 - fan_controller - INFO - Fan 0xff speed set to 45% -INFO: 192.168.5.30:61387 - "POST /api/control/manual HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:57617 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:57617 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:08:03,050 - fan_controller - INFO - Fan 0xff speed set to 32% -2026-02-20 17:08:03,050 - fan_controller - INFO - All fans set to 32% (Temp 51.0°C) -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:57617 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:57617 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:57617 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:57617 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:57617 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:149: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - self._sessions[token] = (username, datetime.utcnow() + timedelta(days=7)) -INFO: 127.0.0.1:53770 - "POST /api/auth/login HTTP/1.1" 200 OK -INFO: 127.0.0.1:53786 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 127.0.0.1:46972 - "POST /api/auth/login HTTP/1.1" 200 OK -2026-02-20 17:10:19,582 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -2026-02-20 17:10:19,744 - fan_controller - INFO - Manual fan control enabled -INFO: 127.0.0.1:46980 - "POST /api/control/auto HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 127.0.0.1:33742 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:10:34,455 - fan_controller - INFO - Fan 0xff speed set to 30% -2026-02-20 17:10:34,456 - fan_controller - INFO - All fans set to 30% (Temp 50.0°C) -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:11:07,821 - fan_controller - INFO - Fan 0xff speed set to 32% -2026-02-20 17:11:07,822 - fan_controller - INFO - All fans set to 32% (Temp 51.0°C) -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:11:54,564 - fan_controller - INFO - Fan 0xff speed set to 30% -2026-02-20 17:11:54,564 - fan_controller - INFO - All fans set to 30% (Temp 50.0°C) -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:12:24,621 - fan_controller - INFO - Fan 0xff speed set to 32% -2026-02-20 17:12:24,622 - fan_controller - INFO - All fans set to 32% (Temp 51.0°C) -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET / HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -2026-02-20 17:12:50,306 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -INFO: 192.168.5.30:55959 - "POST /api/curves/active HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:12:51,151 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -INFO: 192.168.5.30:55959 - "POST /api/curves/active HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -2026-02-20 17:13:04,319 - fan_controller - INFO - Saved config to /home/devmatrix/projects/fan-controller-v2/data/config.json -2026-02-20 17:13:04,478 - fan_controller - INFO - Manual fan control enabled -INFO: 192.168.5.30:55959 - "POST /api/control/auto HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -/home/devmatrix/projects/fan-controller-v2/web_server.py:156: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC). - if datetime.utcnow() > expiry: -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK -INFO: 192.168.5.30:55959 - "GET /api/status HTTP/1.1" 200 OK +INFO: 127.0.0.1:34428 - "GET /api/status HTTP/1.1" 200 OK +2026-02-20 17:24:19,530 - fan_controller - INFO - Fan 0xff speed set to 13% +2026-02-20 17:24:19,531 - fan_controller - INFO - All fans set to 13% (Temp 37.0°C)