o
    Li<                     @   s`  d Z ddlZddlZddlZddlmZmZmZ ddlm	Z	m
Z
mZmZmZ edeZe Zdadai Zdai Ze
eeee	ejjdZdd	 Zd
d ZdefddZdefddZdd Zdd Z dd Z!ej"ddgddd Z#ej"ddgddd Z$ej"ddgdd d! Z%ej"d"dgdd#d$ Z&ej"d%dgdd&d' Z'ej"d(dgdd)d* Z(dS )+a#  
WifiSwitch: relay + temperature/humidity node.

Device reports to:
  POST /wifiswitch/reading

Device polls server for desired relay state and reboot:
  POST /wifiswitch/api/poll

SolarMon dashboard can control the device via:
  POST /wifiswitch/api/set_relay
  POST /wifiswitch/api/reboot
    N)	BlueprintResponserequest)MYSQL_DATABASE
MYSQL_HOSTMYSQL_PASSWORD
MYSQL_PORT
MYSQL_USER
wifiswitchF)hostportuserpassworddatabasecursorclassc                   C   s   t jdi tS )N )pymysqlconnect	DB_CONFIGr   r   r   -/var/www/html/Server/blueprints/wifiswitch.pyget_db0   s   r   c              	   C   s   |   }|d W d    n1 sw   Y  |   tB tr+	 W d    d S |    }|dtf | d u}|sH|d |   W d    n1 sRw   Y  daW d    d S 1 sdw   Y  d S )Na]  
            CREATE TABLE IF NOT EXISTS WifiSwitchStatus (
                id INT AUTO_INCREMENT PRIMARY KEY,
                created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,

                unit_id VARCHAR(16) NOT NULL,
                node_name VARCHAR(50) DEFAULT NULL,

                temp FLOAT NULL,
                humid FLOAT NULL,
                relay_on TINYINT(1) NOT NULL,
                temp_rule_enabled TINYINT(1) NOT NULL DEFAULT 0,

                mac VARCHAR(24) NULL,
                ip VARCHAR(45) NULL,

                firmware_version VARCHAR(24) NULL
            )
            a  
                SELECT 1
                FROM information_schema.columns
                WHERE table_schema=%s
                  AND table_name='WifiSwitchStatus'
                  AND column_name='temp_rule_enabled'
                LIMIT 1
                zWALTER TABLE WifiSwitchStatus ADD COLUMN temp_rule_enabled TINYINT(1) NOT NULL DEFAULT 0T)cursorexecutecommit_state_lock_wifi_switch_schema_checkedr   fetchone)conncurhas_colr   r   r   ensure_wifi_switch_table4   s2   

"r    unit_idc                 C   sP   t  | tv rtt| W  d    S 	 W d    d S 1 s!w   Y  d S N)r   _temp_rule_enabled_pendingboolpopr!   r   r   r   _pop_temp_rule_enabledh   s   $r'   c                 C   sL   t  | tv rt| W  d   S 	 W d   dS 1 sw   Y  dS )z+Pop one-time identity update for a unit_id.N)r   _identity_pending_by_unit_idr%   r&   r   r   r   _pop_identity_updateo   s   $r)   c                 C   sF   t | tr| S t | ttfr| dkS t | tr!|   }|dv S d S )Nr   )1trueonyes)
isinstancer$   intfloatstrstriplower)vsr   r   r   _parse_boolw   s   

r6   c                   C   sF   t  trda	 W d   dS 	 W d   dS 1 sw   Y  dS )z6Pop pending reboot once; return 'reboot' or 'nosleep'.FNrebootnosleep)r   _switch_reboot_pendingr   r   r   r   _pop_reboot_command   s   $r:   c                   C   s0   t  ttW  d    S 1 sw   Y  d S r"   )r   r$   _relay_desiredr   r   r   r   _get_desired_relay   s   $r<   z/readingPOST)methodsc                  C   s6  zdt jddd} | stddddW S | d}| d}| d	}| d
}| d}| d}| d}| d}| d}	|du sP|du sP|du sP|du rXtddddW S t|tra| sitddddW S | dd }t|trx|nd }|r|dd nd}zt|}
W n tt	fy   tdddd Y W S w zt|}W n tt	fy   tdddd Y W S w t
|}|du rtddddW S t
|}|du rd}t|tr|nd dd pd}t|tr|nd dd pd}t|	tr|	nd dd pd}	t }z<t| | !}|d|||
||r!dnd|r'dnd|||	f	 W d   n	1 s9w   Y  |  W |  n|  w t }t }tjd||dd d!}t|d"ddW S  tjyw   td#d$dd Y S  ty } zttjdt|d%d d!d$ddW  Y d}~S d}~ww )&z;Accept relay + AHT10 reading and store in WifiSwitchStatus.Tforcesilentz.{"ok":false,"error":"Invalid or missing JSON"}  application/jsonstatusmimetyper!   	node_nametemphumidrelay_ontemp_rule_enabledmacipfirmware_versionNz@{"ok":false,"error":"Missing unit_id, temp, humid, or relay_on"}z9{"ok":false,"error":"unit_id must be a non-empty string"}    2   z,{"ok":false,"error":"temp must be a number"}z-{"ok":false,"error":"humid must be a number"}z4{"ok":false,"error":"relay_on must be boolean-like"}F   -   a  
                    INSERT INTO WifiSwitchStatus
                        (unit_id, node_name, temp, humid, relay_on, temp_rule_enabled, mac, ip, firmware_version)
                    VALUES
                        (%s, %s, %s, %s, %s, %s, %s, %s, %s)
                       r   okcommandrJ   ,:
separators   z%{"ok":false,"error":"Database error"}  rV   error)r   get_jsonr   getr.   r1   r2   r0   	TypeError
ValueErrorr6   r   r    r   r   r   closer:   r<   jsondumpsr   Error	Exception)datar!   rG   rH   rI   rJ   rK   rL   rM   rN   temp_fhumid_f
relay_on_btemp_rule_enabled_br   r   rW   desired_relaybodyer   r   r   reading   s   








 """


.rr   z	/api/pollc               
   C   sR  zt jdddp	i } | d}| d}| d}|du s&t|tr&| s.tddd	d
W S | dd }|}|}t }t }t	|}t
|}d||d}	|durV||	d< |durh|d|	d< |d|	d< tj|	dd}
td| d| d| dd t|
dd	d
W S  ty } zttjdt|ddddd	d
W  Y d}~S d}~ww )z7Return desired relay state and one-time reboot command.Tr?   r!   rJ   rN   N'{"ok":false,"error":"unit_id required"}rB   rC   rD   rO   rU   rK   new_unit_idnew_node_namerX   r[   z[WifiSwitch] api_poll unit_id=z desired_relay=z cmd=flushr]   Fr_   r^   )r   ra   rb   r.   r1   r2   r   r:   r<   r'   r)   rf   rg   printri   )rj   r!   rJ   rN   _rW   ro   rK   identity_updateresp_objrp   rq   r   r   r   api_poll  s6   


.r|   z/api/set_relayc                  C   s6  zwt jdddp	i } | d}t|}|du rtddddW S t tt}t|att}W d   n1 s8w   Y  t jd	d
}|rP|dd j	dddnd}t
d|  d| d| dt j d|
dd ttjd|ddddddW S  ty } zttjd	t|ddddddW  Y d}~S d}~ww )z-Set desired relay on/off (active-high relay).Tr?   rJ   Nz5{"ok":false,"error":"relay_on required (true/false)"}rB   rC   rD   F)cacher]   zutf-8replace)errorsrP   z$[WifiSwitch] api_set_relay received=z parsed_relay_on=z	 (before=z) ct=z raw_preview=rv   )rV   rJ   rX   r[   r_   r^   )r   ra   rb   r6   r   r   r$   r;   get_datadecoderx   content_typerf   rg   ri   r1   )rj   rJ   rm   beforeafterrawraw_previewrq   r   r   r   api_set_relay(  s<   

.r   z/api/set_temp_rule_enabledc               
   C   s  z`t jdddp	i } | d}| d}|du s!t|tr!| s)tdddd	W S | dd
 }t|}|du rAtdddd	W S t t	|t
|< W d   n1 sTw   Y  tdddd	W S  ty } zttjdt|dddddd	W  Y d}~S d}~ww )zSet a pending temp_rule_enabled flag for the device.

    Device will consume it once on the next poll and persist it to EEPROM.
    Tr?   r!   rK   Nrs   rB   rC   rD   rO   z={"ok":false,"error":"temp_rule_enabled must be boolean-like"}{"ok":true}r]   Fr_   rX   r[   r^   )r   ra   rb   r.   r1   r2   r   r6   r   r$   r#   ri   rf   rg   )rj   r!   rK   	enabled_brq   r   r   r   api_set_temp_rule_enabledL  s<   

r   z/api/set_node_id_namec               
   C   sh  zt jdddp	i } | d}| d}| d}|du s&t|tr&| s.tddd	d
W S |du s;t|tr;| sCtddd	d
W S |du sPt|trP| sXtddd	d
W S | dd }| dd }| dd }t ||dt|< W d   n1 sw   Y  tddd	d
W S  t	y } ztt
jdt|ddddd	d
W  Y d}~S d}~ww )zSet pending node identity for this WifiSwitch.

    Expects JSON:
      { "unit_id": "<current_id>", "new_unit_id": "<new_id>", "new_node_name": "<name>" }

    Device will consume it once on the next poll and persist it to EEPROM.
    Tr?   r!   rt   ru   Nrs   rB   rC   rD   z+{"ok":false,"error":"new_unit_id required"}z-{"ok":false,"error":"new_node_name required"}rO   rQ   )rt   ru   r   r]   Fr_   rX   r[   r^   )r   ra   rb   r.   r1   r2   r   r   r(   ri   rf   rg   )rj   r!   rt   ru   rq   r   r   r   api_set_node_id_namet  sP   	


r   z/api/rebootc                   C   sB   t 
 daW d   n1 sw   Y  tddd tddddS )	z<Set pending reboot; device will reboot on next poll/reading.TNz#[WifiSwitch] api_reboot pending setrv   r   r]   rC   rD   )r   r9   rx   r   r   r   r   r   
api_reboot  s
   r   ))__doc__rf   	threadingr   flaskr   r   r   configr   r   r   r   r	   __name__bpLockr   r;   r9   r#   r   r(   cursors
DictCursorr   r   r    r1   r'   r)   r6   r:   r<   routerr   r|   r   r   r   r   r   r   r   r   <module>   sN    

4

q
$
#
'
5