// A solar installer's meter readings over Modbus: the request for an energy meter's registers
// (RTU on RS-485, or TCP), its answer read into volts, amps, watts and kWh (floats in word-swapped
// order), an exception explained, and the frames to write a set point.
//
//   quillo run modbus.qwe      then open http://localhost:8080/meter
//   MODBUS_HOST=192.168.1.80 quillo run modbus.qwe      and http://localhost:8080/live

use "modbus.qwer"

route GET /meter {
    let answer = modbus_response("01 03 10 66 66 43 66 00 00 41 4C 99 9A 45 37 00 12 D6 87 E2 97", { mode: "rtu" })?
    let floats = modbus_values(slice(answer.values, 0, 6), "f32", "CDAB", 1.0)?
    {
        request: modbus_request(3, 0, 8, { mode: "rtu", unit: 1 })?,
        request_tcp: modbus_request(3, 0, 8, { mode: "tcp", unit: 1, transaction: 42 })?,
        registers: answer.values,
        voltage: floats[0], current: floats[1], power: floats[2],
        energy_kwh: modbus_values(slice(answer.values, 6, 8), "u32", "ABCD", 0.01)?[0],
        crc: modbus_crc("01 03 00 00 00 0A")?,
    }
}

route GET /write = {
    set_point: modbus_request(16, 100, modbus_registers(48.5, "f32", "CDAB")?, { unit: 3 })?,
    relay_on: modbus_request(5, 12, true, { unit: 3 })?,
    seen_by_device: modbus_parse_request(modbus_request(16, 100, [1, 2, 3], { unit: 3 })?, "rtu")?,
    refused: modbus_response("01 83 02 C0 F1", {})?.error,
    bad_crc: modbus_response("01 03 02 00 0A 00 00", {}).error,
}

route GET /live {
    let host = env("MODBUS_HOST", null) ?? reply 503 "set MODBUS_HOST to a Modbus TCP device's address"
    modbus_tcp_read(host, 1, 3, 0, 8, 2000)?
}
