+
    ]i5r                     Z   R t ^ RIt^ RIt^ RIt^ RIt^ RIt^ RIHt ^ RIH	t	H
t
HtHt ^ RIHtHtHtHtHt  ^ RIHtHtHt ^ RIHtHtHt ]P6                  P9                  ]P6                  P;                  ]4      4      t]	! R] ]P6                  PC                  ]R	4      R
R7      t"R t#R R lt$R!R lt%R t&R t'R t(Rs)Rs*R t+R t,R t-R t.]"P_                  R4      R 4       t0]"P_                  RR.R7      R 4       t1]"P_                  RRR.R7      R 4       t2R#   ] d
    RtRt^t Li ; i)"z
SolarMon: solar dashboard (Victron, Growatt, EPEver, batteries) and temp-sensor API.
Uses MySQL shop_stats; replicates appearance of PHP SolarMon index.php.
Weather for System column from Open-Meteo (Columbia, MS).
N)datetime)	Blueprintrender_templaterequestResponse)
MYSQL_HOST
MYSQL_PORTMYSQL_DATABASE
MYSQL_USERMYSQL_PASSWORD)WEATHER_LATWEATHER_LONWEATHER_CACHE_MINUTESg     @?@)ensure_ota_tablesget_latest_version_strversion_lesssolarmonsolarmon_staticz/solarmon/static)static_folderstatic_url_pathc            	          \         P                  ! \        \        \        \
        \        \         P                  P                  R 7      # ))hostportuserpassworddatabasecursorclass)	pymysqlconnectr   r   r
   r   r	   cursors
DictCursor     blueprints/solarmon.py	_get_connr$   '   s/    ??OO.. r"   c                     V '       d   W9  g   W,          e   W,          R8X  d   V#  \        W,          4      #   \        \        3 d    Tu # i ; i)N )float	TypeError
ValueErrorrowkeydefaults   &&&r#   _floatr.   2   sG    #.CH$4BSXz" s   : AAc                 t    V '       d   W9  g   W,          f   V# \        W,          4      P                  4       # )N)strstripr*   s   &&&r#   _strr2   ;   s*    #.CH$4sx=  r"   c           
     B   V e-   \        V \        4      '       d   V P                  4       '       g   R#  \        V 4      pRTu;8:  d   R8:  d:   M R# \        ^ \        ^d\        TR,
          R,          ^d,          ^4      4      4      # R#   \        \
        3 d     R# i ; i)u   
Single-cell Li-ion: return bar fill 0–100 from voltage (2.5V–4.3V).
Bar width = position in voltage range, not charge percentage.
Ng      @g333333@g?)	
isinstancer0   r1   r'   r)   r(   maxminround)batvs   & r#   _bat_voltage_bar_pctr:   A   s    
 {z#s++CIIKK#J a3 1c#ua#g_s%:A>?@@ 	" s   B	 	BBc                X    W,
          p\        TP                  4       4      pT^ 8  d   ^ pT^<,          pT^<,          pT^,          pT^<8  d   R# T^<8  d   T RT^8w  d   R R2# R R2# T^8  d   T RT^8w  d   R R2# R R2# T RT^8w  d   R R2# R R2#   \          d     R# i ; i)zY
Return a short, human-readable delta like '5 minutes ago', '2 hours ago', '3 days ago'.
r&   zjust nowz minutesz agoz hourz day)	Exceptioninttotal_seconds)dtnowdeltasecondsminuteshoursdayss   &&     r#   _human_timedeltarG   R   s     %%%'(G{mGrMEB;D||'A#!>dCC2!>dCCrzUaZc8==R8==V4tqy166b166#  s   B B)(B)c                $    \        V 4       V P                  4       ;_uu_ 4       pVP                  RV34       VP                  4       pRRR4       X'       g   R# \	        WR,          4      #   + '       g   i     L,; i  \
         d     R# i ; i)zDReturn latest firmware version string for OTA project slug, or None.z+SELECT id FROM ota_projects WHERE slug = %sNid)r   cursorexecutefetchoner   r=   )connslugcurr+   s   &&  r#   _ota_latest_version_by_slugrP   l   so    	$[[]]cKKEwO,,.C  %dI66 ]  s.   #B  $A-	B  B  -A=	8B   BBc                F   V f   R# \        V 4      pV^ 8X  d   R# VR9   d   V^8:  d   R# R# VR9   d   R# ^3Tu;8:  d   ^C8:  d   M MV^=8  d   R# R# ^GTu;8:  d
   ^M8:  d    R#  ^PTu;8:  d
   ^R8:  d    R	#  ^UTu;8:  d
   ^V8:  d    R
#  ^_Tu;8:  d
   ^c8:  d    R#  R# R# )z;Map WMO weather code to short condition string for display.r&   ClearzPartly cloudyOvercastFogRainDrizzleSnowShowerszSnow showersThunderstorms)         )-   0   )r>   )codecs   & r#   _wmo_weathercode_to_conditionsra      s    |D	AAvI~"#q&8j8H}	Q}"}bv/i/	Q}"} 	Q}"} 	Q}"} 	Q}"} r"   c                 |   RP                  \        \        4      p  \        P                  P                  V RR/R7      p\        P                  P                  V^
R7      ;_uu_ 4       p\        P                  ! VP                  4       P                  4       4      pRRR4        XP!                  R4      ;'       g    / pTP!                  R4      ;'       g    / pTP!                  R	4      ;'       g    . pTP!                  R
4      ;'       g    . pTP!                  R4      ;'       g    . p/ p	TP!                  R4      e&   \#        \%        TP!                  R^ 4      ^4      4      MRT	R&   \'        T4      ^ 8  d(   T^ ,          e   \#        \%        T^ ,          ^4      4      MRT	R&   \'        T4      ^ 8  d(   T^ ,          e   \#        \%        T^ ,          ^4      4      MRT	R&   \)        \'        T4      ^ 8  d
   T^ ,          MR4      T	R&   RT	R&   \'        T4      ^8  d(   T^,          e   \#        \%        T^,          ^4      4      MRT	R&   \'        T4      ^8  d(   T^,          e   \#        \%        T^,          ^4      4      MRT	R&   RT	R&   \)        \'        T4      ^8  d
   T^,          MR4      T	R&   RT	R&   T	#   + '       g   i     EL'; i  \        P                  P                  \        P                  P                  \        P                  \        3 d     R# i ; i  \*        \,        \.        3 d     R# i ; i)z
Fetch today/tomorrow weather for Columbia, MS from Open-Meteo.
Returns dict with w_conditions, w_temp, w_tempmax, w_tempmin, wt_conditions, wt_tempmax, wt_tempmin
or None on failure.
zhttps://api.open-meteo.com/v1/forecast?latitude={:f}&longitude={:f}&timezone=America/Chicago&current_weather=true&temperature_unit=fahrenheit&daily=temperature_2m_max,temperature_2m_min,weathercodez
User-AgentzSolarMon/1.0)headers)timeoutNcurrent_weatherdailytemperature_2m_maxtemperature_2m_minweathercodetemperaturer&   w_temp	w_tempmax	w_tempminw_conditionsw_icon
wt_tempmax
wt_tempminwt_tempwt_conditionswt_icon)formatr   r   urllibr   RequesturlopenjsonloadsreaddecodeerrorURLError	HTTPErrorJSONDecodeErrorOSErrorgetr0   r7   lenra   
IndexErrorr(   r)   )
urlreqrespdatacwrf   maxesminscodesouts
             r#   _fetch_weather_open_meteor      s   	s f[+&	 
nn$$S<2P$Q^^##C#44::diik0023D 5XX'(..B!''R		./552yy-.44"		-(..BCE66-CXCdE"&&":A>?jlH69%j1nqI]3uU1Xq12ceK58Y]tAwGZ3uT!Wa01`bK<UVWU1X]abNH7:5zA~%PQ(J^CeAh 23dfL69$i!mQH[Cd1gq 12acLI=#e*WX.eAh^bcOI
/ 544LL!!6<<#9#94;O;OQXY , 	:. sb   AK (3J9K $L! <L! L! 2L! L! (FL! 9K
	K 
K ALL!L;:L;c                    \         P                  ! 4       p \        e   \        \        4      M^p\        e7   \
        e/   V \
        ,
          P                  4       pW!^<,          8  d   \        # \        4       pVe   VsV sV# )z?Return cached weather or fetch and cache. Returns dict or None.)r   rA   r   r>   _weather_cache_weather_cache_timer?   r   )rA   
cache_minsrB   weathers       r#   _get_weather_cachedr      sp     ,,.C/D/P*+VXJ!&9&E**99;?"!!')G !Nr"   c                    / RRbRRbRRbRRbRRbRRbRRbR	RbR
RbRRbRRbR^ bR^ bRRbRRbRRbRRb/ RRbRRbRRbRRbRRbRRbRRbRRbRRbR^ bR^ bR ^ bR!RbR". bR#RbR$RbR%RbCR&RR'RR(RR)RR*. R+. R,R-R.R-/Cp  \        4       p / pRl F  p\        Y4      Y#&   K  	  \	        4       pT'       d   TP                  RR4      T R&   TP                  RR4      T R&   TP                  RR4      T R&   TP                  RR4      T R&   TP                  RR4      T R&   TP                  R
R4      T R
&   TP                  RR4      T R&   TP                  RR4      T R&   TP                  R	R4      T R	&   TP                  RR4      T R&   TP                  4       ;_uu_ 4       pTP                  R3Rm4       TP                  4       pT'       Ed   \        TR44      pT'       d
   TR5,          MRT R&   \        \        TR64      4      T R&   \        \        TR74      4      T R&   TP                  R84      pTe   TR8w  d    \        T4      pT^ 8  d   R9T R&   M\        T^,          ^<,          4      p	\        T\        T	^,          ^<,          4      ,
          ^<,          4      p
\        Y^,          ^<,          ^<,          T
^<,          ,           ,
          ^<,          4      pT	 R:T
 R;T R<2T R&    R-R-R-4       TP                  4       ;_uu_ 4       pTP                  R=4       TP                  4       pT'       dr   \        TR4      p\        TR4      p\        TR4      p\        TR4      p\        TR4      pYR&   YR&   YR&   YR&   TT R&   Y,           T,           T,           T,           T R&   R-R-R-4       TP                  4       ;_uu_ 4       pTP                  R>4       TP                  4       pT'       d^   \        TR4      p\        TR4      p\        TR4      p\        TR4      p\        TR4      pTT,           T,           T,           T,           T R&   R-R-R-4       TP                  4       ;_uu_ 4       pTP                  R?4       TP                  4       pT'       d2   \        TR4      \        TR4      ,           \        TR4      ,           T R!&   R-R-R-4       R@ pTP                  4       ;_uu_ 4       pTP                  RA4       TP                  4       p. pT FY  p\!        TRB4      p\        TRC4      pTP#                  RDTRE\        \        TRF4      4      RG\        TRH4      RTRIT! T4      /4       K[  	  TT R"&   R-R-R-4       TP                  4       ;_uu_ 4       pTP                  RJ4       TP                  4       pT'       Ed^   TP                  RK4      ;'       g    TP                  R#4      ;'       g    Rp\%        T\        \        34      '       d   \'        T4      pM\'        T4      P)                  4       pRn F9  pTP+                  T4      '       g   K  TR-\-        T4      )  P)                  4       p M	   \        T4      pT^	,          ^,          ^ ,           RL RM2T R#&   \!        TRN4      T R$&   \!        TRO4      pTP/                  RPR4      P/                  RQRR4      P/                  RSRT4      pTT R%&   \!        TR&4      T R&&   \!        TR'4      T R'&   \!        TR(4      T R(&   R-R-R-4       TP                  4       ;_uu_ 4       p TP                  RU4       TP                  RV4       TP                  4       p\2        P4                  ! 4       pTP                  R/4      p T F  p!\7        T!P                  RW4      4      T!RX&   T!P                  RW4      p"T"e   T"R8w  d    \        T"4      RY RZ2T!R[&   MRT!R[&   T!P                  R\4      p#T#'       d   \9        T#T4      T!R]&   MRT!R]&   \;        T ;'       d-    T!P                  R^4      ;'       d    \=        T!R^,          T 4      4      T!R_&   T T!R`&   R/T!Ra&   K  	  TT R*&   R-R-R-4        TP                  4       ;_uu_ 4       p TP                  Rb4       TP                  Rc4       TP                  4       p\2        P4                  ! 4       pTP                  R04      p$T F  p!\7        T!P                  Rd4      4      T!RX&   T!P                  Rd4      p"T"e   T"R8w  d    \        T"4      RY RZ2T!R[&   MRT!R[&   T!P                  Re4      p%T%'       d.   TT%,
          P?                  4       Ro8  T!Rf&   \9        T%T4      T!R]&   M
RgT!Rf&   RT!R]&   \;        T$;'       d-    T!P                  R^4      ;'       d    \=        T!R^,          T$4      4      T!R_&   T$T!R`&   R0T!Ra&   K  	  TT R+&   R-R-R-4        TP                  4       ;_uu_ 4       pTP                  Rh4       TP                  4       pT'       d   TP                  Re4      '       d7   \A        T4      p\2        P4                  ! 4       p\9        TRe,          T4      TR]&   TP                  R14      p&\;        T&;'       d-    TP                  R^4      ;'       d    \=        TR^,          T&4      4      TR_&   T&TR`&   R1TRa&   Y`R,&   R-R-R-4        TP                  4       ;_uu_ 4       pTP                  Ri4       TP                  4       pT'       Ed   TP                  Re4      '       d7   \A        T4      p\2        P4                  ! 4       p\9        TRe,          T4      TR]&   TP                  Rj4      e   \;        TP                  Rj4      4      TRj&   TP                  Rk4      e   \;        TP                  Rk4      4      TRk&   TP                  R24      p'\;        T';'       d-    TP                  R^4      ;'       d    \=        TR^,          T'4      4      TR_&   T'TR`&   R2TRa&   Y`R.&   R-R-R-4       TPE                  4         \        T R,          T R,          R5,          ,
          ^4      T R)&   T #   \        P                   d    T u # i ; i  \        \        3 d     E	Li ; i  + '       g   i     E	L; i  + '       g   i     E	L+; i  + '       g   i     EL; i  + '       g   i     EL1; i  + '       g   i     EL; i  \        \        3 d    T;'       g    RT R#&    ELi ; i  + '       g   i     EL-; i  \        P0                   d     ELi ; i  \        \        3 d    \'        T"4      T!R[&    ELi ; i  + '       g   i     EL/; i  \        P0                   d     ELi ; i  \        \        3 d    \'        T"4      T!R[&    ELi ; i  + '       g   i     EL; i  \        P0                   d     EL)i ; i  + '       g   i     ELE; i  \        P0                  \        PB                  3 d     ELpi ; i  + '       g   i     EL+; i  \        P0                  \        PB                  3 d     ELVi ; i  TPE                  4        i ; i  \        \        3 d
    RT R)&    T # i ; i)pzTFetch all data for the main dashboard; return a dict with defaults for missing data.rm   r&   rl   rk   rn   ro   rq   rp   rr   rs   rt   vic_voltageg        currentvic_socvic_ttgz	No RecordGw1PGw2PGw3PEP1PEP2Psolar_powerGw1CGw2CGw3CEP1CEP2Ctotal_currentGw1LoadGw2LoadGw3Loadtotal_inv_current	batteries	shed_temp
shed_humidup_timedateuserstasksconsumptiontemps_latestmoisture_latestpump_latestNwifiswitch_latest	wifitempsmoisturemeterpumpcontrol
wifiswitchzSELECT V, P, I, SOC, TTG FROM VEDirect WHERE Name = %s AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1VgMbP?ISOCTTGInfinatez Days z Hrs z Minaa  
                SELECT
                  (SELECT ((((Ppv1H * 10) << 16) + (Ppv1L * 10)) * .1) FROM Growatt
                   WHERE Name = 'Growatt 1' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw1P,
                  (SELECT ((((Ppv1H * 10) << 16) + (Ppv1L * 10)) * .1) FROM Growatt
                   WHERE Name = 'Growatt 2' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw2P,
                  (SELECT ((((Ppv1H * 10) << 16) + (Ppv1L * 10)) * .1) FROM Growatt
                   WHERE Name = 'Growatt 3' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw3P,
                  (SELECT ((((r3103 * 10) << 16) + (r3102 * 10)) * .001) FROM EPEver
                   WHERE Name = 'Epever 01' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS EP1P,
                  (SELECT ((((r3103 * 10) << 16) + (r3102 * 10)) * .001) FROM EPEver
                   WHERE Name = 'Epever 02' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS EP2P
                aW  
                SELECT
                  (SELECT Buck1Curr FROM Growatt WHERE Name = 'Growatt 1' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw1C,
                  (SELECT Buck1Curr FROM Growatt WHERE Name = 'Growatt 2' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw2C,
                  (SELECT Buck1Curr FROM Growatt WHERE Name = 'Growatt 3' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw3C,
                  (SELECT (r3105 * .01) FROM EPEver WHERE Name = 'Epever 01' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS EP1C,
                  (SELECT (r3105 * .01) FROM EPEver WHERE Name = 'Epever 02' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS EP2C
                a
  
                SELECT
                  (SELECT Inv_Curr FROM Growatt WHERE Name = 'Growatt 1' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw1C,
                  (SELECT Inv_Curr FROM Growatt WHERE Name = 'Growatt 2' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw2C,
                  (SELECT Inv_Curr FROM Growatt WHERE Name = 'Growatt 3' AND LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) ORDER BY id DESC LIMIT 1) AS Gw3C
                c                 b    V ^ 8X  d   R# V ^ 8  d   R\        V ^4       R2# R\        V ^4       R2# )    	EqualizedzChar: azDisc: )r7   )r`   s   &r#   _bat_status)fetch_dashboard_data.<locals>._bat_status|  s=    Av"1ua}A..E!QK=**r"   a  
                SELECT b.Name, b.PercentCapacity, b.Voltage, b.Current
                FROM Battery b
                INNER JOIN (
                    SELECT Name, MAX(id) AS max_id
                    FROM Battery
                    WHERE LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE)
                    GROUP BY Name
                ) t ON b.Name = t.Name AND b.id = t.max_id
                ORDER BY b.Name
                NameCurrentnamesocPercentCapacityvoltageVoltagestatuszSELECT shed_Temperature AS shed_temp, shed_Humiditity AS shed_humiditity, `up`, `date`, users, tasks FROM Environment WHERE LastUpdate >= DATE_SUB(NOW(), INTERVAL 5 MINUTE) AND shed_Humiditity <> '' ORDER BY id DESC LIMIT 1shed_Temperaturez.1fu    °Fshed_humiditityupzup rE   hrD   mzFALTER TABLE Temps ADD COLUMN firmware_version VARCHAR(24) DEFAULT NULLaL  
                SELECT t.unit_id, t.node_name, t.temp, t.humid, t.bat, t.entry_date, t.firmware_version
                FROM Temps t
                INNER JOIN (
                    SELECT unit_id, MAX(entry_date) AS max_entry_date
                    FROM Temps
                        WHERE entry_date >= NOW() - INTERVAL 20 MINUTE
                    GROUP BY unit_id
                ) latest ON t.unit_id = latest.unit_id AND t.entry_date = latest.max_entry_date
                    WHERE t.entry_date >= NOW() - INTERVAL 20 MINUTE
                ORDER BY t.unit_id
                r8   bat_bar_pctz.2fz Vbat_display
entry_datelast_seen_agofirmware_versionota_newer_availableota_latest_versionota_project_slugzNALTER TABLE MoistureLevel ADD COLUMN firmware_version VARCHAR(24) DEFAULT NULLa  
                    SELECT m.device_id, m.node_name, m.moisture, m.battery_voltage, m.command, m.firmware_version, m.created_at
                    FROM MoistureLevel m
                    INNER JOIN (
                        SELECT device_id, MAX(id) AS max_id FROM MoistureLevel GROUP BY device_id
                    ) latest ON m.device_id = latest.device_id AND m.id = latest.max_id
                    WHERE m.created_at >= NOW() - INTERVAL 20 MINUTE
                    ORDER BY m.device_id
                    battery_voltage
created_atis_staleFzSELECT id, pressure_psi, pump_on, error_pressure_low, app_state, rssi, ip, mac, firmware_version, created_at FROM PumpStatus ORDER BY created_at DESC LIMIT 1zSELECT id, unit_id, node_name, temp, humid, relay_on, temp_rule_enabled, mac, ip, firmware_version, created_at FROM WifiSwitchStatus ORDER BY created_at DESC LIMIT 1relay_ontemp_rule_enabled)r   r   r   r   )z	Victron 2)u    °Cu   °Cz CCr`   i  )#r$   r   ErrorrP   r   r   rJ   rK   rL   r.   r>   r'   r7   r(   r)   fetchallr2   appendr4   r0   r1   endswithr   replaceOperationalErrorr   rA   r:   rG   boolr   r?   dictProgrammingErrorclose)(defaultsrM   
ota_latestrN   r   rO   r+   r9   ttgrF   rE   rD   gw1gw2gw3ep1ep2c1c2c3c4c5r   rowsr   r   r   raw_tempsuffixr`   r   rA   	ota_tempsrbentry_dtota_moisturecreatedota_pump
ota_switchs(                                           r#   fetch_dashboard_datar     s   +R+R+ 	"+ 		+
 	"+ 	b+ 	b+ 	2+ 	+ 	2+ 	s+ 	1+ 	1+ 	;+ 	+  	!+" 	#+$ 	%+& 	'+( 	s)+* 	++, 	-+. 	/+0 	1+2 	3+4 	5+6 	17+8 	19+: 	1;+< 	S=+> 	R?+@ 	RA+B 	bC+D 	2E+F 	s2tTU+HX{W
OD:4FJ P &''.{{>2'FH^$!(Xr!:HX$+KKR$@H[!$+KKR$@H[!!(Xr!:HX(/OR(HH_%%,[[r%BH\"%,[[r%BH\"")++i"<HY")++i"<HY [[]]cKK+ 	 ,,.Cs3$78!e)c'&)&c*:&;#&)&e*<&=#ggen?sby#Cj72<HY/#(rB#7D$)3tby2~1F+F"*L$ME&+!$)b.B)>52:(N!OSU U'G $(&ugU7)4 H %Y/3 @ [[]]cKK ,,.CS&)S&)S&)S&)S&)#& #& #& #& #& *-)c/C*?#*E'9 > [[]]cKK	 ,,.CC(C(C(C(C(,.GbL2,=,B)% * [[]]cKK ,,.C3'&f*==sF@SS ,-  	+ [[]]cKK
 <<>DIC( i0  D3vc+<=>vc95wk'2"   %.H[!5 : [[]]cKK+ ,,.Cs GG./  ww{+  
 he55"8}H"8}224H=F((00#+Ns6{l#;#A#A#C >;hA01A	R/?.DD,IH[) *.c3D)E&#t_ZZr*227C@HHTWX&(##'V#4 $(g$6!$(g$6!G L [[]]cde KK <<>D,,.C"{3I#7e#E- EE%L=Q"W2.3Ahs^2+>-( (*Am$55.)9(C)HAo&)+Ao&+/nn!%%(:";nnQOaMbdm@n,'( +4&'(3$%) * (,H^$W \.	#KK pq 
 ||~lln)~~o>A';AEEBS<T'UAm$/0A}b627(3r/BAm, ,.-(eeL1G),w(E(E(G'(Q*-=gs-K/*(-*-//*/3$xx/A)Bxx|TUVhTikwGx0A+, /;A*+,;A()- . /3*+U `	#G llnww|,,"3i&lln/?L@QSV/WO,)~~m<H15 ttSWW-?%@tt\RUVhRiksEt2C-. 19C,-.;C*+.1]+# .	#M lln3ww|,,"3i&lln/?L@QSV/WO,wwz*6*.swwz/B*CJww23?37@S8T3U/0!+!=J15"xxsww/A'Bxx|TWXjTkmwGx2C-. 1;C,-.:C*+4701- 8 	

&"'_%))<u)DEq#
 OI == h &z2 9 ]]@ ]]> ]]* ]]. ]]p #I. ;,4NNH[);7 ]]R ++ 4 '	2 2+.q6-(2; ]]d // , !+I6 6/21vAm,63 V '' 		 $ (('*B*BC 		 . (('*B*BC 		
 	

 z" &"%O&s  >
q7 	Dz Br,8rr,Br"r,# z Bs  z >Bs z %As( #z #Bs<+ z At7t7'At7	!t7+)tA?t7 z 3v5uBvu'v="v v9.v'z 0w7 w#
v!Bw#!v=3w#Aw#w#0.w#w7 'x' ?A x Axx.)xx'  y' 8Ay:B4y/y)y1y' 
+z( 7rrr)%r,(r))r,,r=	7	z  s		z s%		z (s9	3	z <t		z t4*t40t73t44t77u		z u$ v#u$$v'v
	v	v
	
vv		z !v:6w#9v::w#=w 	w#w 	 w##w4	.w7 2z 4w7 7xz xz x$	x' "z $x' '%yz yz y$	y' "z $y' '%zz zz z%({{/c                 ,    \        4       p \        R/ V B # )z;Main SolarMon dashboard (same appearance as PHP index.php).)zsolarmon/index.html)r  r   )r   s    r#   indexr  g  s      !D9D99r"   z/moisture/deletePOST)methodsc                    \         P                  ! RR7      ;'       g    / p V P                  R4      ;'       g    RP                  4       pV'       g   \	        RRRR7      #  \        4       p TP                  4       ;_uu_ 4       pTP                  RT34       RRR4       TP                  4        \	        RRR7      TP                  4        #   \        P                   d    \	        R	R
RR7      u # i ; i  + '       g   i     Lf; i  \        P                   d2    TP                  4        \	        RR
RR7      u TP                  4        # i ; i  TP                  4        i ; i)zu
Delete all MoistureLevel records for a given device_id.
Intended to be called from the SolarMon dashboard via AJAX.
T)silent	device_idr&   z{"error": "device_id required"}i  zapplication/json)r   mimetypez!{"error": "database unavailable"}i  z.DELETE FROM MoistureLevel WHERE device_id = %sNz{"success": true}r  z{"error": "delete failed"})r   get_jsonr   r1   r   r$   r   r   rJ   rK   commitr   rollback)payloadr
  rM   rO   s       r#   delete_moisture_devicer  n  s*    d+11rG[)//R668I-'
 	

{[[]]cKK@ 
 	+6HI 	

/ == 
/'
 	

 ] == 
('
 	
 	


 	

sN   "
C -D
 C7$D
 #C43C47D	D
 
3E=E EE E%z/tempsGETc                    \         P                  R8X  d   \         P                  M\         P                  p V P	                  RR4      P                  4       pV P	                  RR4      P                  4       pV P	                  RR4      P                  4       pV P	                  RR4      P                  4       pV P	                  RR4      P                  4       pV P	                  RR4      P                  4       pV P	                  R	R4      P                  4       pV P	                  R
4      ;'       g    RP                  4       R,          ;'       g    Rp\        P                  ! 4       P                  R4      p	 \        4       p
 RpT
P                  4       ;_uu_ 4       pTP                  RT34       TP                  4       pT'       df   TP	                  R4      '       dO   \!        \#        TR,          4      P                  4       4      ^ 8  d!   \#        TR,          4      P                  4       pRRR4       T
P                  4       ;_uu_ 4       pTP                  RYY#YEYgT3	4       RRR4       T
P%                  4        T'       d"   \        RT R2RR7      T
P'                  4        # \        RRR7      T
P'                  4        #   \        P                   d    \        RRR7      u # i ; i  + '       g   i     L; i  + '       g   i     L; i  \        P                   d1    T
P)                  4        \        RRR7      u T
P'                  4        # i ; i  T
P'                  4        i ; i)z
Temp-sensor API: accept id, temp, humid, mac, ip, bat, name.
Insert reading; return '~' or '@Com:<command>~' (parameterized queries).
r  rI   r&   temphumidmacipr8   r   r   :N   NNz%Y-%m-%d %H:%M:%S~z
text/plainr  zESELECT command FROM Temps WHERE unit_id = %s ORDER BY id DESC LIMIT 1commandzINSERT INTO Temps (unit_id, entry_date, temp, humid, mac, ip, bat, node_name, firmware_version) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)z@Com:)r   methodargsformr   r1   r   utcnowstrftimer$   r   r   r   rJ   rK   rL   r   r0   r  r   r  )r  unit_idr  r  r  r  r8   	node_namer   r   rM   r  rO   r+   s                 r#   	temps_apir"    s    #>>U27<<DhhtR &&(G88FB%%'DHHWb!'')E
((5"

#
#
%C	$		!	!	#B
((5"

#
#
%C$**,I!34::AACCHPPD"++,?@J4{[[]]cKKW
 ,,.Cswwy))c#c)n2E2K2K2M.NQR.Rc)n-335  [[]]cKK>d3CL\]  	eG9A.F 	

 l3
 	

; == 4l334
 ] ] == 4l33

	4 	

sz   5
K  L AK)AK)+ L K<#L L $L "K&%K&)K9	4L <L	L 2MM MM M)gQuV)r   )r&   )3__doc__ry   osr   urllib.errorrv   urllib.requestr   flaskr   r   r   r   configr   r   r	   r
   r   r   r   r   ImportErrorblueprints.otar   r   r   pathdirnameabspath__file___BP_DIR__name__joinbpr$   r.   r2   r:   rG   rP   r   r   ra   r   r   r  router  r  r"  r!   r"   r#   <module>r4     sS  
  	     ? ? FF
 S R ''//"''//(3
4'',,w(9:&	!"74  0&R Tn #: : 
vh/' 0'T (UFO,/ -/G  KKs   
D D*)D*