<file_sep>#!/usr/bin/env python
import requests
import json

class Tg:
    base_url="https://api.telegram.org/bot"
    def __init__(self, token):
        self.token = token
    
    def send_msg(self,tgid,msg):
        construct_url=f"{self.base_url}{self.token}/sendMessage" 
        header = {'Content-type': 'application/json'}
        payload = {"chat_id":tgid,"text":msg}
        r=requests.post(construct_url,data=json.dumps(payload),headers=header)
        if r.status_code==200:
            print("msg send")
        else:
            print(r.status_code)
            print("something goes wrong",r.headers)
        
<file_sep>#!/usr/bin/env python
import os
from pprint import pprint
from datetime import datetime
import time
import logging

from ansible_vault import Vault         
from ansible.parsing.vault import VaultLib, VaultSecret
from ansible.constants import DEFAULT_VAULT_ID_MATCH

import waviot
import tg

logging.basicConfig(filename='app.log', filemode='w', format='%(name)s - %(levelname)s - %(message)s', level=logging.DEBUG)

def get_creds_vault(vault_file,vault_password):
    try:
        vault = Vault(vault_password)
        secrets = vault.load(open(vault_file).read())
    except:
        err=f"can't decode {vault_file}"
        print(err)
        logging.debug(f"ERROR: {err}")
        sys.exit()
                              
    #####HACK for ansible version https://github.com/tomoh1r/ansible-vault/pull/34      
    #vault = VaultLib([(DEFAULT_VAULT_ID_MATCH, VaultSecret(vault_password.encode()))])  
    #secrets = yaml.safe_load(vault.decrypt(open(vault_file).read()))                    
    #####                                                                               
#    print(secrets)                                                                    
    return secrets          


def send_alarm(creds,msg):
    sender=tg.Tg(creds['tg_token'])
    chat_id=creds['chat_id']
    sender.send_msg(chat_id,msg)
    #sender.send_msg(,msg)
    logging.debug(f"send msg to {chat_id} : {msg}")
    
def lk_water_event(tg_token,event):
    modem=event['modem_id']
    event_type=event['event_type']
    dec_code=event['code']['decimal']
    descr=event['description']
    date_time=event['date_time']
    if dec_code==40:
        alarm_msg=(f"{date_time} модем: {modem} событие: {descr} ")
        print(alarm_msg)
        send_alarm(tg_token,alarm_msg)

def lk_event_parser(tg_token,response):
    #pprint(response)
    if response['status']=="ok":
        for gmt_timestamp,event in response['events'].items():
            event_type=event['event_type']
            if event_type=='water':
                lk_water_event(tg_token,event)
    else:
        print("error status in response")


def helper_list_modems(modems):
    modem_hex=[]
    modem_dec=[]
    for modem in modems.keys():
        modem_hex.append(modem)
        modem_dec.append(str(int(modem,16)))
    modems_list=[modem_hex,modem_dec]
    
    return modems_list

#def wa_search_water

def roll_event_parser(response,significant_diff):
    
    significant_diff=float(significant_diff)
    alarms=[]
    alarm={}
    for modem in response.keys():
        prev_value=0
        for record in response[modem]:
            if record['protocol']=='water7':
                current_value=record['data']['0']['value']
                timestamp=record['timestamp']
                alarm_key=f'{timestamp}-{modem}'
                diff=prev_value-current_value
                if round(current_value)>=20:
                    alarm[alarm_key]={'timestamp':timestamp,'modem_id':modem,'value':current_value,'state':'За пределами измерений'}
                    #alarms.append(alarm)
                elif round(current_value)<=4:
                    alarm[alarm_key]={'timestamp':timestamp,'modem_id':modem,'value':current_value,'state':'За пределами измерений'}
                    #alarms.append(alarm)
                elif diff>significant_diff:
                    alarm[alarm_key]={'timestamp':timestamp,'modem_id':modem,'value':current_value,'state':'Падение давления'}
                    #alarms.append(alarm)
                elif current_value<5:
                    alarm[alarm_key]={'timestamp':timestamp,'modem_id':modem,'value':current_value,'state':'Давление меньше 1бар'}
                elif current_value>7:
                    alarm[alarm_key]={'timestamp':timestamp,'modem_id':modem,'value':current_value,'state':'Давление больше уставки '}

                logging.debug(f"modem {modem} event water7 timestamp:{timestamp}, current_value: {current_value}, prev_value: {prev_value}, diff: {diff}")
                prev_value=current_value
            elif record['protocol']=='water6': #and record['tag']=='water6.pair.1':
                code=record['payload'][-8:-4]
                timestamp=record['timestamp']
                alarm_key=f'{timestamp}-{modem}'
                if code=='0028':
                    alarm[alarm_key]={'timestamp':timestamp,'modem_id':modem,'value':'протечка','state':'Замыкание контактов'}
                    #alarms.append(alarm)
                logging.debug(f"event water6 timestamp:{timestamp}, code: {code}")
            else:
                print(f"no parser for proto {record['data']}")
                logging.debug(f"no parser for proto {record['data']}")
    return alarm

def alarm_manage(creds,alarms,modems):
    #pprint(modems)
    utc_offset=10800
    for key,alarm in alarms.items():
        alarm_modem_id=hex(int(alarm['modem_id']))[2:]
        date_time=datetime.utcfromtimestamp(alarm['timestamp']+utc_offset).strftime('%Y-%m-%d %H:%M:%S')
        modem_name=modems[alarm_modem_id]['elem_name']
        temperature=modems[alarm_modem_id]['temperature']
        max_pr=16 #max I for presure sensor
        pressure=((alarm['value']-4)/16)*max_pr
        alarm_message=f"{date_time} модем: {alarm_modem_id} ({alarm['modem_id']})) температура: {temperature}\n Место установки: {modem_name} событие: {alarm['state']} ({pressure:.2f}бар) - ток {alarm['value']}"
        if alarm_modem_id!='7a48ad':
            send_alarm(creds,alarm_message)



def main():
    now_date=int(datetime.now().timestamp())
    readabledate=datetime.utcfromtimestamp(now_date+10800).strftime('%Y-%m-%d %H:%M:%S')
    old_date=int(datetime.now().timestamp())-3600
    
    print(f"run {now_date}")
    logging.debug(f"run {now_date}({readabledate})")

    vault_pass=os.getenv('VAULT',default='unknown')
     try:
        creds=get_creds_vault(os.path.dirname(os.path.abspath(__file__))+'/secret1.yml',vault_pass)
    except OSError as e:
        err=f"cant'open secret file {e}"
        logging.debug(f"ERROR: {err}")
        print(err)
        sys.exit(e.errno)

 
        
    wa=waviot.Waviot(creds['login'],creds['password'])
    wa.get_login()
    #$modems=wa.get_modems_intree('827132')
    modems=wa.get_modems_intree('195984')
    
    mlist=helper_list_modems(modems)
    get_values=wa.get_request(f"https://api.waviot.ru/api/roll?modem_id={','.join(mlist[1])}&from={old_date}&to={now_date}")

    #response=wa.get_request("https://lk.waviot.ru/api.data/get_events/?modem_id=721D7C,7A48AC&from=1614187030&to=1614188330")
    #wa.print_raw_response()
    #wa.print_response_roll()
    alarms=roll_event_parser(get_values,0.5)
    alarm_manage(creds,alarms,modems)
    #lk_event_parser(creds['tg_token'],response)

if __name__=="__main__":
    logging.debug(f"==============START==================")
    while True:
        main()
        time.sleep(1800)
    



<file_sep>#!/usr/bin/env python
import requests
import json

def get_login(inlogin,inpass):
    WAVIOT_JWT=False
    payload = {"login":inlogin,"password":<PASSWORD>}
    header = {'Content-type': 'application/json','X-requested-with': 'XMLHttpRequest'}
    r=requests.post('https://auth.waviot.ru/?action=user-login',data=json.dumps(payload),headers=header)
    if r.status_code==200:
        try:
            WAVIOT_JWT=json.loads(r.text)['WAVIOT_JWT']
            print(WAVIOT_JWT)
        except:
            print("no WAVIOT_JWT")
    else:
        print(r.status_code)
        print("something goes wrong",r.headers)
    return WAVIOT_JWT

def get_request(url,JWT):
    header = {'Content-type': 'application/json',
              'X-requested-with': 'XMLHttpRequest',
              'Authorization': 'bearer ' + JWT }
    r=requests.get(url,headers=header)
    if r.status_code==200:
        try:
            response=json.loads(r.text)
        except:
            print("no response")
    else:
        print("error",r.status_code)
        print("something goes wrong",r.headers)
    return response
   
def parse_response_roll(injson):
    for modem in injson:
        print(modem)
        for record in injson[modem]:
            print("NEW RECORD\n {} \n===========\n".format(record))
            try:
                print("timestamp: {}, snr: {}, rssi: {}".format(
                          record['timestamp'],
                          record['snr'],record['rssi']))
            except:
                print("no")
            try:
                for sensor in record['data'].values():
                    print("sensor:{},value:{}".format(sensor['name'],sensor['value']))
                print("\n==========\n")
            except:
                print ("no")
    return True

if __name__=="__main__":
    murl='https://api.waviot.ru/api/roll?modem_id=8013997&limit=10'
    login=""
    passw=""
    JWT=get_login(login,passw)
    resp=get_request(murl,JWT)
    parse_response_roll(resp)


<file_sep>ansible==4.2.0
ansible-base==2.10.6
ansible-vault==2.1.0
certifi==2022.12.7
cffi==1.14.5
chardet==4.0.0
cryptography==3.4.6
idna==2.10
Jinja2==2.11.3
MarkupSafe==1.1.1
packaging==20.9
pkg-resources==0.0.0
pycparser==2.20
pyparsing==2.4.7
PyYAML==5.4.1
requests==2.25.1
urllib3>=1.26.5
<file_sep># waviot-api
<file_sep>#!/usr/bin/env python
import requests
import json
from pprint import pprint

class Waviot:
    login_url='https://auth.waviot.ru/?action=user-login'
    get_tree_url='https://lk.waviot.ru/api.tree/get_tree/'
    get_modems_url='https://lk.waviot.ru/api.tree/get_modems/'
    
    def __init__(self, login, password):
        self.login = login
        self.password = <PASSWORD>

    def get_login(self):
        WAVIOT_JWT=False
        payload = {"login":self.login,"password":self.<PASSWORD>}
        header = {'Content-type': 'application/json','X-requested-with': 'XMLHttpRequest'}
        r=requests.post(self.login_url,data=json.dumps(payload),headers=header)
        if r.status_code==200:
            try:
                WAVIOT_JWT=json.loads(r.text)['WAVIOT_JWT']
                #print(WAVIOT_JWT)
                self.WAVIOT_JWT=WAVIOT_JWT
            except:
                print("no WAVIOT_JWT")
        else:
            print(r.status_code)
            print("something goes wrong",r.headers)
        #return WAVIOT_JWT

    def get_request(self,url):
        #print(url)
        header = {'Content-type': 'application/json',
                  'X-requested-with': 'XMLHttpRequest',
                  'Authorization': 'bearer ' + self.WAVIOT_JWT}
        r=requests.get(url,headers=header)
        if r.status_code==200:
            try:
                reqresponse=json.loads(r.text)
                self.response=reqresponse
            except:
                print(f"no response {r.text}")
        else:
            print("error",r.status_code)
            print("something goes wrong - headers:\n",r.headers)
        return reqresponse

    def print_raw_response(self):
        print(self.response)


    def print_response_roll(self):
        for modem in self.response:
            print(f"---{modem}---")
            for record in self.response[modem]:
                print("===== NEW RECORD {} =======\n {} \n===========\n".format(record['protocol'],record))
                try:
                    print("timestamp: {}, snr: {}, rssi: {}, station: {}".format(
                          record['timestamp'],
                          record['snr'],record['rssi'],record['station_id']))
                except:
                    print("no")
                if record['protocol']=='water7':
                    try:
                        for sensor in record['data'].values():
                            print("sensor:{},value:{}".format(sensor['name'],sensor['value']))
                        print("\n==========\n")
                    except:
                        print ("no")
                elif record['protocol']=='water6':
                    code=record['payload'][-8:-4]
                    print(code)
                else:
                    print(f"no parser for proto {record['data']}")

            print("----------------")
        return True


    
    def get_subtree(self,elem_id):
        url=f'{self.get_tree_url}?id={elem_id}'
        reqresponse=self.get_request(url)
        subtree={}
        if reqresponse.get('tree')!=None:
            subtree=reqresponse['tree']
        return subtree

 
    def get_modems_inelem(self,elem_dict):
        elem_id=elem_dict['id']   
        url=f'{self.get_modems_url}?id={elem_id}'
        reqresponse=self.get_request(url)
        modems={}
        if reqresponse.get('modems')!=None:
            for modem in reqresponse.get('modems'):
                modems[modem['id']]={'flavor_id':modem['flavor_id'],
                                     'temperature':modem['temperature'],
                                    'battery':modem['battery'],
                                    'elem_name':elem_dict['name'],
                                    'elem_type':elem_dict['type']
                                    }
        return modems
    
    def get_modems_intree(self,elem_id):
        elements=self.get_subtree(elem_id)
        modems={}
        for element in elements.values():
           
            modems.update(self.get_modems_inelem(element))
        return modems

