'''
Loop to run every minutes

* * * * * /usr/bin/python3 /var/www/nebuleair_pro_4g/NPM/get_data_modbus_loop.py ttyAMA5

saves data (avaerage) to a json file /var/www/nebuleair_pro_4g/NPM/data/data.json
saves data (all) to a sqlite database

first time running the script?
sudo mkdir /var/www/nebuleair_pro_4g/NPM/data
sudo touch /var/www/nebuleair_pro_4g/NPM/data/data.json
'''

import serial
import sys
import crcmod
import time
import json
import os
import sqlite3
import smbus2  # For RTC DS3231
from datetime import datetime


# Ensure a port argument is provided
if len(sys.argv) < 2:
    print("Usage: python3 get_data_modbus.py <serial_port>")
    sys.exit(1)

port = '/dev/' + sys.argv[1]

# Initialize serial communication
try:
    ser = serial.Serial(
        port=port,
        baudrate=115200,
        parity=serial.PARITY_EVEN,
        stopbits=serial.STOPBITS_ONE,
        bytesize=serial.EIGHTBITS,
        timeout=0.5
    )
except Exception as e:
    print(f"Error opening serial port {port}: {e}")
    sys.exit(1)

# 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])

# Log request frame
print(f"Request frame: {request.hex()}")

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

# RTC Module (DS3231) Setup
RTC_I2C_ADDR = 0x68  # DS3231 I2C Address
bus = smbus2.SMBus(1)

def bcd_to_dec(bcd):
    return (bcd // 16 * 10) + (bcd % 16)

def get_rtc_time():
    """Reads time from RTC module (DS3231)"""
    try:
        data = bus.read_i2c_block_data(RTC_I2C_ADDR, 0x00, 7)
        seconds = bcd_to_dec(data[0] & 0x7F)
        minutes = bcd_to_dec(data[1])
        hours = bcd_to_dec(data[2] & 0x3F)
        day = bcd_to_dec(data[4])
        month = bcd_to_dec(data[5])
        year = bcd_to_dec(data[6]) + 2000
        return datetime(year, month, day, hours, minutes, seconds).strftime("%Y-%m-%d %H:%M:%S")
    except Exception as e:
        print(f"RTC Read Error: {e}")
        return "N/A"

# Initialize storage for averaging
num_samples = 6
channel_sums = [0] * 5  # 5 channels

#do not start immediately to prevent multiple write/read over NPM serial port
time.sleep(3)

# Loop 6 times to collect data every 10 seconds
for i in range(num_samples):
    print(f"\nIteration {i+1}/{num_samples}")
    ser.write(request)
    rtc_timestamp = get_rtc_time()

    try:
        byte_data = ser.readline()
        formatted = ''.join(f'\\x{byte:02x}' for byte in byte_data)
        print(f"Raw Response: {formatted}")

        if len(byte_data) < 23:
            print("Incomplete response, skipping this sample.")
            time.sleep(9)
            continue

        # Extract and process the 5 channels
        channels = []
        for j in range(5):
            lsw = int.from_bytes(byte_data[3 + j*4 : 5 + j*4], byteorder='little')
            msw = int.from_bytes(byte_data[5 + j*4 : 7 + j*4], byteorder='little')
            raw_value = (msw << 16) | lsw
            channels.append(raw_value)

        # Accumulate sum for each channel
        for j in range(5):
            channel_sums[j] += channels[j]

        # Print collected values
        print(f"Timestamp (RTC): {rtc_timestamp}")
        for j in range(5):
            print(f"Channel {j+1}: {channels[j]}")

        
        # Save the individual reading to the database
        cursor.execute('''
        INSERT INTO data (timestamp, PM_ch1, PM_ch2, PM_ch3, PM_ch4, PM_ch5)
        VALUES (?, ?, ?, ?, ?, ?)
        ''', (rtc_timestamp, channels[0], channels[1], channels[2], channels[3], channels[4]))

        conn.commit()

    except Exception as e:
        print(f"Error reading data: {e}")

    # Wait 10 seconds before next reading
    time.sleep(10)

# Compute the average values
channel_means = [int(s / num_samples) for s in channel_sums]

# Create JSON structure
data_json = {
    "channel_1": channel_means[0],
    "channel_2": channel_means[1],
    "channel_3": channel_means[2],
    "channel_4": channel_means[3],
    "channel_5": channel_means[4]
}

# Print final JSON data
print("\nFinal JSON Data (Averaged over 6 readings):")
print(json.dumps(data_json, indent=4))

# Define JSON file path
output_file = "/var/www/nebuleair_pro_4g/NPM/data/data.json"

# Write results to a JSON file
try:
    with open(output_file, "w") as f:
        json.dump(data_json, f, indent=4)
    print(f"\nAveraged JSON data saved to {output_file}")
except Exception as e:
    print(f"Error writing to file: {e}")

# Close serial connection
ser.close()
