'''
  _   _ ____  __  __ 
 | \ | |  _ \|  \/  |
 |  \| | |_) | |\/| |
 | |\  |  __/| |  | |
 |_| \_|_|   |_|  |_|

Script to get NPM data via Modbus
need parameter: port
/usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus.py

Modbus RTU
[Slave Address][Function Code][Starting Address][Quantity of Registers][CRC]

Pour récupérer les 5 cannaux (a partir du registre 0x80)
Donnée actualisée toutes les 10 secondes

Request
\x01\x03\x00\x80\x00\x0A\xE4\x1E

\x01        Slave Address (slave device address)
\x03        Function code (read multiple holding registers)
\x00\x80    Starting Address (The request starts reading from holding register address 0x80 or 128)
\x00\x0A    Quantity of Registers (Requests to read 0x0A or 10 consecutive registers starting from address 128)
\xE4\x1E    Cyclic Redundancy Check (checksum )

'''

import serial
import requests
import json
import sys
import crcmod
import sqlite3

# Connect to the SQLite database
conn = sqlite3.connect("/var/www/nebuleair_pro_4g/sqlite/sensors.db")
cursor = conn.cursor()

def load_config(config_file):
    try:
        with open(config_file, 'r') as file:
            config_data = json.load(file)
        return config_data
    except Exception as e:
        print(f"Error loading config file: {e}")
        return {}

# Load the configuration data
config_file = '/var/www/nebuleair_pro_4g/config.json'
config = load_config(config_file)
npm_solo_port = config.get('NPM_solo_port', '')  #port du NPM solo

ser = serial.Serial(
    port=npm_solo_port,
    baudrate=115200,
    parity=serial.PARITY_EVEN,
    stopbits=serial.STOPBITS_ONE,
    bytesize=serial.EIGHTBITS,
    timeout = 0.5
)

# Define Modbus CRC-16 function
crc16 = crcmod.predefined.mkPredefinedCrcFun('modbus')

# Request frame without CRC
data = b'\x01\x03\x00\x80\x00\x0A'

# Calculate CRC
crc = crc16(data)
crc_low = crc & 0xFF
crc_high = (crc >> 8) & 0xFF

# Append CRC to the frame
request = data + bytes([crc_low, crc_high])
#print(f"Request frame: {request.hex()}")

ser.write(request)

#GET RTC TIME from SQlite
cursor.execute("SELECT * FROM timestamp_table LIMIT 1")
row = cursor.fetchone()  # Get the first (and only) row
rtc_time_str = row[1]  # '2025-02-07 12:30:45'

while True:
    try:
        byte_data = ser.readline()
        formatted = ''.join(f'\\x{byte:02x}' for byte in byte_data)
        #print(formatted)

        # Extract LSW (first 2 bytes) and MSW (last 2 bytes)
        lsw_channel1 = int.from_bytes(byte_data[3:5], byteorder='big')  
        msw_chanel1 = int.from_bytes(byte_data[5:7], byteorder='big') 
        raw_value_channel1 = (msw_chanel1 << 16) | lsw_channel1

        lsw_channel2 = int.from_bytes(byte_data[7:9], byteorder='big') 
        msw_chanel2 = int.from_bytes(byte_data[9:11], byteorder='big')  
        raw_value_channel2 = (msw_chanel2 << 16) | lsw_channel2

        lsw_channel3 = int.from_bytes(byte_data[11:13], byteorder='big')  
        msw_chanel3 = int.from_bytes(byte_data[13:15], byteorder='big')  
        raw_value_channel3 = (msw_chanel3 << 16) | lsw_channel3

        lsw_channel4 = int.from_bytes(byte_data[15:17], byteorder='big')  
        msw_chanel4 = int.from_bytes(byte_data[17:19], byteorder='big')  
        raw_value_channel4 = (msw_chanel1 << 16) | lsw_channel4

        lsw_channel5 = int.from_bytes(byte_data[19:21], byteorder='big')  
        msw_chanel5 = int.from_bytes(byte_data[21:23], byteorder='big') 
        raw_value_channel5 = (msw_chanel5 << 16) | lsw_channel5

        print(f"Channel 1 (0.2->0.5): {raw_value_channel1}")
        print(f"Channel 2 (0.5->1.0): {raw_value_channel2}")
        print(f"Channel 3 (1.0->2.5): {raw_value_channel3}")
        print(f"Channel 4 (2.5->5.0): {raw_value_channel4}")
        print(f"Channel 5 (5.0->10.): {raw_value_channel5}")

        cursor.execute('''
        INSERT INTO data_NPM_5channels (timestamp,PM_ch1, PM_ch2, PM_ch3, PM_ch4, PM_ch5) VALUES (?,?,?,?,?,?)'''
        , (rtc_time_str,raw_value_channel1,raw_value_channel2,raw_value_channel3,raw_value_channel4,raw_value_channel5))

        # Commit and close the connection
        conn.commit()


        break
    except KeyboardInterrupt:
        print("User interrupt encountered. Exiting...")
        time.sleep(3)
        exit()
    except:
        # for all other kinds of error, but not specifying which one
        print("Unknown error...")
        time.sleep(3)
        exit()

conn.close()
