peninquen / modbus-energy-monitor-arduino Goto Github PK
View Code? Open in Web Editor NEWA class to collect data from a energy monitor that uses modbus protocol.
License: Apache License 2.0
A class to collect data from a energy monitor that uses modbus protocol.
License: Apache License 2.0
ModbusSensor solo almacena errores o excepciones producidas en el canal Modbus. Organizar los bits para incluir más información:
slave_exception
error comunicado por el esclavo con el código de función 0x80master_error
error generado por el Master. Se superpone con algunos excepciones del esclavo.registered
: el valor ya ha sido leido y registrado desde la ultima vez que se actualizó.El procesador llevará dos o más procesos:
MBSerial
.Ya hay una entrada en modbusSerial es confuso!!
Si la intención es que puedan usarse mas de un bus sobrecargar la función.
En la version 0.5.2 hay dos errores importantes, el primero corregido:
Se pueden hacer pruebas en modo debug sin ningún SDM para supervisar la salida
Funciones de ModbusMaster para poner/quitar de la cola de peticiones un sensor en particular.
Preparando el camino al configurador y a peticiones directas, fuera de cola
En Modbus-Energy-Monitor-Arduino/Modbus-Energy-Monitor-Arduino/ModbusSensor.cpp no se que utilidad tiene la variable _framesize. ?
No he tenido tiempo seguir las evoluciones, me lío con tantas versiones......
Creo que configSDM120.ino ha sido machacado, restaurar versión anterior.
Me puedes explicar como funciona o donde puedo leerlo.
No lo habia visto nunca!!!!!
Para hacer más eficiente el código y permitir la ejecución de otros procesos sin retrasos es necesario eliminar delayMicroseconds()
que puede introducir una parada en el procesador de hasta 11.458 microsegundos a 2400 bauds.
Ahora está así:
case SENDING:
if ((*_hwSerial).availableForWrite() == SERIAL_TX_BUFFER_SIZE - 1) { //TX buffer empty
// time to send last byte and required empty time space
delayMicroseconds(_T2_5);
La función comprueba el buffer TX, cuando está vacio significa que el último byte se encuentra en el registro de TX del UART, por lo que se para hasta asegurar que se ha enviado y además le datos un espacio vacio de T1.5.
Para la nueva función se establece un timer sendMicros
y un intervalo sending_interval
antes de la función sendBuffer()
y en el siguiente estado SENDING
realizaría la comparación para cambiar al siguiente estado.
Me preocupa que el UART valla mas deprisa o despacio que, con lo que se pueden presentar dos problemas:
Voy a hacer pruebas de timing en microsegundos para confirmar, me falta un osciloscopio para analizarlo correctamente.
Aunque se sale del objeto de la librería, el siguiente paso es definir el tipo de base de datos a la que enviar los datos, definir la trama a enviar:
Fecha/hora: ¿AAAMMDDhh:mm:ss?
valor: ¿float? ¿entero con parte decimal? ¿cadena ASCII?
etiqueta del valor:¿mandamos una ristra CSV y el orden define qué parametro es? ¿cada parametro va acompañado de su etiqueta?
No tengo experiencia en web server ni en SQL, será lo siguiente...
Mi idea es introducirme en el funcionamiento de la raspi y ver diferentes opciones, una que he encontrado es cacti
http://trasteandoarduino.com/2014/04/27/monitorizacion-del-sistema-con-cacti-y-arduino-parte-1-instalacion/
¿Alguna experiencia o idea?
Decidir qué funciones se hacen inline o no para mejorar velocidad o para ahorrar memoria.
Hi,
I want to build this great project but I cannot find the connection diagram. To which pins do I need to connect the MAX485 adapter? I would like to use an Arduino Mega board and serial2 = pin 16(TX) and 17(RX), but the code says Txenable = pin 17. Should this be changed?
Please upload a connection diagram, that would make things much more clear to me or describe where pins R1(RO), R2(RE), R3(DE) and R4(DI) should be connected to.
Did I interpret the RS485 settings in the SDM630 correct when set to?
Addr: 001
Baud: 9.6k
par1: none
stop: 2
Thanks a lot!
He realizado la conexion de un medidor utilizando la libreria normal de sdm.h pero no logro entender como al conectar otro medidores en paralelo A y B, como deberia especificar el numero del esclavo y como extraer los parametros que requiero.
Great work, I am using Your Sketch on a Mega for my Home Automation and it works fine, Thank You for that.
But now I wanted to port it to a DUE, because the Mega is running out of Speed.
I have problems compiling Your Sketch on my DUE causing a HardwareSerial error.
Working on a MAC Version 10.11.2, Arduino 1.65 gives this error:
Arduino:` 1.6.5 (Mac OS X), Platine: "Arduino Due (Programming Port)"
ModbusSensor.cpp: In member function 'void modbusMaster::begin(uint16_t, uint8_t)':
ModbusSensor.cpp:205: error: no matching function for call to 'HardwareSerial::begin(uint16_t&, uint8_t&)'
(__hwSerial).begin(baudrate, byteFormat);
^
ModbusSensor.cpp:205:42: note: candidate is:
In file included from /Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/Arduino.h:195:0,
from ModbusSensor.h:16,
from ModbusSensor.cpp:25:
/Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/HardwareSerial.h:29:18: note: virtual void HardwareSerial::begin(long unsigned int)
virtual void begin(unsigned long);
^
/Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/HardwareSerial.h:29:18: note: candidate expects 1 argument, 2 provided
ModbusSensor.cpp: In member function 'boolean modbusMaster::available()':
ModbusSensor.cpp:251: error: 'class HardwareSerial' has no member named 'availableForWrite'
if ((__hwSerial).availableForWrite() == SERIAL_TX_BUFFER_SIZE - 1) { //TX buffer empty
^
ModbusSensor.cpp:251: error: 'SERIAL_TX_BUFFER_SIZE' was not declared in this scope
if ((*_hwSerial).availableForWrite() == SERIAL_TX_BUFFER_SIZE - 1) { //TX buffer empty
^
no matching function for call to 'HardwareSerial::begin(uint16_t&, uint8_t&)'
Then I found this Thread in the Arduino Forum:
http://forum.arduino.cc/index.php?topic=142753.0
I changed "HardwareSerial" to "USARTClass" in Your ModbusSensor.cpp( one time ) and in ModbusSensor.h ( two times ).
But now I get this error:
Arduino: 1.6.5 (Mac OS X), Platine: "Arduino Due (Programming Port)"
ModbusSensor.cpp: In member function 'void modbusMaster::begin(uint16_t, uint8_t)':
ModbusSensor.cpp:205: error: call of overloaded 'begin(uint16_t&, uint8_t&)' is ambiguous
(__hwSerial).begin(baudrate, byteFormat);
^
ModbusSensor.cpp:205:42: note: candidates are:
In file included from /Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/variants/arduino_due_x/variant.h:39:0,
from /Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/Arduino.h:201,
from ModbusSensor.h:16,
from ModbusSensor.cpp:25:
/Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/USARTClass.h:111:10: note: void USARTClass::begin(uint32_t, USARTClass::USARTModes)
void begin(const uint32_t dwBaudRate, const USARTModes config);
^
/Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/USARTClass.h:111:10: note: no known conversion for argument 2 from 'uint8_t {aka unsigned char}' to 'USARTClass::USARTModes'
/Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/USARTClass.h:112:10: note: void USARTClass::begin(uint32_t, UARTClass::UARTModes)
void begin(const uint32_t dwBaudRate, const UARTModes config);
^
/Users/abe/Library/Arduino15/packages/arduino/hardware/sam/1.6.7/cores/arduino/USARTClass.h:112:10: note: no known conversion for argument 2 from 'uint8_t {aka unsigned char}' to 'UARTClass::UARTModes'
ModbusSensor.cpp: In member function 'boolean modbusMaster::available()':
ModbusSensor.cpp:251: error: 'SERIAL_TX_BUFFER_SIZE' was not declared in this scope
if ((__hwSerial).availableForWrite() == SERIAL_TX_BUFFER_SIZE - 1) { //TX buffer empty
^
call of overloaded 'begin(uint16_t&, uint8_t&)' is ambiguous
Will You please help me porting Your great work to an Arduino DUE?
Hello there,
i like to interface this nice SDM230 device with ESP32 chip. Can you please add support for ESP32 chip.
Orientado al SDM630, ¿creamos un sensor trifasico, con los valores de las tres fases en formato float, recogida de una sola trama modbus?
en contra, implica un nuevo objeto con funciones adaptadas que complica el ModbusMaster.
a favor, mayor velocidad en la lectura y tratamiento.
En caso de solo utilizar el SDM120, no debe implicar mayor carga de recursos
https://www.arduino.cc/en/Serial/Write
Si cambiamos el bucle for por (*_MBSerial).write(_framePtr,8);, el sketch se reduce unos 24Bytes,.
Cosmopaco, Puedes volver a intentar fusionar los manuales? a ver si aprendo GitHub...
Hello,
I'm trying to use ...\Stabile version\Modbus-Energy-Monitor-Arduino.ino with my Arduino UNO and SDM120C, but I can't recive any respons from energy meter.... Arduino TX diode is blink interval, but any data wasn't respond.(RX don't blink) Can you help me?
My connection:
SDM120 -> max485 module
B - B
A - A
max485 module ->Arduino
Vcc - 5V
GND - GND
DE - RE - PIN2
DI - PIN1 TX
R0 - PIN0 RX
Code modifiation:
Lines:
#define SERIAL_OUTPUT 0 // Serial port 0
#define TxEnablePin 2 //DE and RE PIN
I'll be very gratefull for any help.
/**********************************************************************
ModbusEnergyMonitor example
An example to collect data from a Modbus energy monitor using ModbusSensor class
to datalogger, include a RTC DS3231 and a SD card
version 0.4 BETA 31/12/2015
Author: Jaime García @peninquen
License: Apache License Version 2.0.
**********************************************************************/
/*
*/
#define SERIAL_OUTPUT 0
#if SERIAL_OUTPUT
# define SERIAL_BEGIN(...) Serial.begin(__VA_ARGS__)
# define SERIAL_PRINT(...) Serial.print(__VA_ARGS__)
# define SERIAL_PRINTLN(...) Serial.println(__VA_ARGS__)
#else
# define SERIAL_BEGIN(...)
# define SERIAL_PRINT(...)
# define SERIAL_PRINTLN(...)
#endif
#include "ModbusSensor.h"
#include "SDMdefines.h"
#define MB_SERIAL_PORT &Serial // Arduino has only one serial port, Mega has 3 serial ports.
// if use Serial 0, remember disconect Tx (pin0) when upload sketch, then re-conect
#define MB_BAUDRATE 2400 // b 2400
#define MB_BYTEFORMAT SERIAL_8N2 // Prty n
#define TxEnablePin 2
#define ID_1 1 // id 001 modbus id of the energy monitor
#define REFRESH_INTERVAL 5000 // refresh time, 5 SECONDS
#define WRITE_INTERVAL 10000UL // values send to serial port, 1 minute ( 60 * 1000)
#define KWH_2_WS 36000000
// multiplication factor, store value as an integer
#define VOL_FAC 10
#define CUR_FAC 100
#define POW_FAC 10
#define PFA_FAC 100
#define FRE_FAC 10
#define ENE_FAC 100
// global variables to poll, process and send values
modbusSensor volt(ID_1, VOLTAGE, CHANGE_TO_ZERO);
modbusSensor curr(ID_1, CURRENT, CHANGE_TO_ZERO);
modbusSensor pwr(ID_1, POWER, CHANGE_TO_ZERO);
modbusSensor enrg(ID_1, IAENERGY, HOLD_VALUE);
modbusSensor freq(ID_1, FREQUENCY, CHANGE_TO_ZERO);
modbusSensor aPwr(ID_1, APOWER, CHANGE_TO_ZERO);
modbusSensor pwrFact(ID_1, PFACTOR, CHANGE_TO_ONE);
uint16_t voltage, maxVoltage, minVoltage; // integer, factor x10
uint16_t current, maxCurrent, minCurrent; // integer, factor x100
uint16_t power, maxPower, minPower; // integer, factor x10
uint16_t lastEnergy, energy, avgPower; // integer, factor x100
uint16_t frequency, maxFreq, minFreq; // integer, factor x100
uint16_t aPower, maxApower, minApower; // integer, factor x10
uint16_t powerFactor, maxPF, minPF; // integer, factor x100
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
boolean firstData;
void setup() {
Serial.begin(9600);
MBSerial.config(MB_SERIAL_PORT, TxEnablePin, REFRESH_INTERVAL);
MBSerial.begin(MB_BAUDRATE, MB_BYTEFORMAT);
delay(95);
Serial.println("time(s), maxVolt(V), minVolt(V), maxCurr(A) minCurr(A), maxPower(W), minPower(W), maxApPower(VA), minApPower(VA), maxFreq(Hz), minFreq(Hz), AvgPower (W), Energy(Kwh)");
firstData = false;
power = 0;
maxPower = 0; // in case it has been recorded, use it
minPower = 0;
lastEnergy = 0; // in case it has been recorded, use it
energy = lastEnergy;
}
void loop() {
sei();
if (MBSerial.available()) {
voltage = volt.read(VOL_FAC);
current = curr.read(CUR_FAC);
power = pwr.read(POW_FAC);
aPower = aPwr.read(POW_FAC);
frequency = freq.read(FRE_FAC);
energy = enrg.read(ENE_FAC);
if (!firstData) {
if (maxVoltage < voltage) maxVoltage = voltage;
if (minVoltage > voltage) minVoltage = voltage;
if (maxCurrent < current) maxCurrent = current;
if (minCurrent > current) minCurrent = current;
if (maxPower < power) maxPower = power;
if (minPower > power) minPower = power;
if (maxApower < aPower) maxApower = aPower;
if (minApower > aPower) minApower = aPower;
if (maxFreq < frequency) maxFreq = frequency;
if (minFreq > frequency) minFreq = frequency;
if (maxPower < power) maxPower = power;
if (minPower > power) minPower = power;
}
else {
maxVoltage = voltage;
minVoltage = voltage;
maxCurrent = current;
minCurrent = current;
maxPower = power;
minPower = power;
maxApower = aPower;
minApower = aPower;
maxFreq = frequency;
minFreq = frequency;
firstData = false;
}
}
currentMillis = millis();
if (currentMillis - previousMillis >= WRITE_INTERVAL) {
previousMillis = currentMillis;
avgPower = (energy - lastEnergy) * KWH_2_WS / (WRITE_INTERVAL / 1000); //average power KWh/s to W
lastEnergy = energy;
firstData = true;
Serial.print(currentMillis / 1000);
Serial.print(",");
Serial.print((float)maxVoltage / VOL_FAC, 1);
Serial.print(",");
Serial.print((float)minVoltage / VOL_FAC, 1);
Serial.print(",");
Serial.print((float)maxCurrent / CUR_FAC, 2);
Serial.print(",");
Serial.print((float)minCurrent / CUR_FAC, 2);
Serial.print(",");
Serial.print((float)maxPower / POW_FAC, 2);
Serial.print(",");
Serial.print((float)minPower / POW_FAC, 2);
Serial.print(",");
Serial.print((float)maxApower / POW_FAC, 2);
Serial.print(",");
Serial.print((float)minApower / POW_FAC, 2);
Serial.print(",");
Serial.print((float)maxFreq / FRE_FAC, 2);
Serial.print(",");
Serial.print((float)minFreq / FRE_FAC, 2);
Serial.print(",");
Serial.print((float)avgPower / ENE_FAC, 2);
Serial.print(",");
Serial.println((float)energy / ENE_FAC, 2);
}
}
Crear un fichero cabecera, con macros o funciones de apoyo.
Las variables a leer o escribir en SDM estan diferentes formatos HEX, BCD y Float. Añadir las funciones o macros swapFloat, intToFloat, intToHex.
El programa de arduino debe estar orientado a la gestión de eventos, si el envío-recepción de mensajes dura 40- 70 ms durante ese tiempo no puede ejecutar ningún otro módulo (salvo por interrupciones).
objetivo: modificar las funciones sendFrame() y readBuffer() para enviar/leer un byte, retornar y mantener el _state hasta que haya terminado de enviar/recibir el frame.
modo:
Creo que se debería renombrar como WAITING_FOR_TURNAROUND .
O como el objeto que realmente se ejecuta POLL_INTERVAL,
Creo que son términos más adecuados, y no se confunden con los usos que le dan las librerías de comunicación.
He estado viendo otras librerías modbus y ésta, junto con simpleModbusSerial, de la que nació como idea, es la única que hace el proceso de muestreo periódico de sensores dentro de la función.
Esto hace que, si el objetivo es muestrear uno o varios sensores cada cierto tiempo, sea una librería muy directa.
Por contra, cuando se trata de ser más flexible, con peticiones variables según otros parámetros que pueda tener el usuario de la librería, obligue a disconnect()
y connect()
y actuar sobre POLL_INTERVAL según requiera.
Estoy pensando en que MBSerial
pueda funcionar con un solo objeto modbusSenor o con un array de objetos modbusSensor que se le pase como argumento.
La principal ventaja es utilizar un solo buffer de RX, por contra, perdemos compatibilidad con ESP8266.
Hola! Llevo días (muchos) intentando comunicar un Arduino UNO con un CVM mini mediante un RS485 a TTL pero no me acerco ni de lejos. He consultado decenas de páginas pero con la generación de la petición no consigo avanzar.
He visto que uno de los puntos a realizar en el futuro era una versión para este analizador de red. Si has publicado algo o sabes dónde puedo encontrarlo te lo agradecería infinitamente.
Estoy intentado monitorizar una instalación fotovoltaica aislada con varios generadores de apoyo en una aplicación móvil (que ya la tengo hecha con Unity). Tiene una parte gráfica en la que se ve qué elemento es el que está generando la energía para la instalación y muestra los parámetros correspondientes.
En fin, si me pudieras ayudar, te lo agradecería infinitamente.
Tamaño original compilación actual.
Sketch uses 8.956 bytes (3%) of program storage space. Maximum is 253.952 bytes.
Global variables use 767 bytes (9%) of dynamic memory, leaving 7.425 bytes for local variables.
Maximum is 8.192 bytes.
Funciones sobrecargadas enlazadas.
Sketch uses 8.836 bytes (3%) of program storage space. Maximum is 253.952 bytes.
Global variables use 767 bytes (9%) of dynamic memory, leaving 7.425 bytes for local variables. Maximum is 8.192 bytes.
Modificación.
modbusSensor::modbusSensor(uint8_t id, uint16_t adr, uint8_t hold, uint8_t sizeofValue) {
_value = new uint8_t[sizeofValue];
_frame = new uint8_t[8];
_frameSize = 8;
_frame[0] = id;
_frame[1] = READ_INPUT_REGISTERS;
_frame[2] = adr >> 8;
_frame[3] = adr & 0x00FF;
_frame[4] = 0x00;
_frame[5] = 0x02;
uint16_t crc = calculateCRC(_frame, 6);
_frame[6] = crc & 0x00FF;
_frame[7] = crc >> 8;
_status = MB_TIMEOUT;
_hold = hold;
MBSerial.connect(this);
}
// Constructor
modbusSensor::modbusSensor(uint8_t id, uint16_t adr, uint8_t hold) {
modbusSensor( id, adr, hold, 4);
}
La siguiente sobrecarga se complica un poco, aunque también se podría enlazar.
Creo que el constructor:
modbusSensor::modbusSensor(uint8_t id, uint8_t fc, uint16_t adr, uint8_t hold, uint8_t sizeofValue) {
Seria mas correcto:
modbusSensor::modbusSensor(uint8_t id, uint16_t adr, uint8_t hold, uint8_t sizeofValue, uint8_t fc) {
Si puedes añadir mas datos deberían ir en forma ascendente, no intercalados.
Con el objetivo de que sea 'Arduino-like' los nombres de las funciones en las librerías tienen que ser consistentes con las que existen en otras librerías de Arduino, devolver tipos similares. De esta forma un sketch puede ser casi identico y tomar datos por el bus serial, por ModbusRTU, por un pin de pulsos, etc.
Ejemplo MBSerial.read() es equivalente a Serial.read().
Proponer nombres de variables y constantes más descriptivas, o que se ajusten a nombres en otras librerías Arduino.
Permitiría utilizar un Arduino UNO, Nano, etc.
La velocidad está limitada por el SDM120 a 9600.
Empezar pruebas a 2400 bauds.
Tengo claro:
ModbusMaster, el objeto que gestiona el canal serie con el protocolo Modbus RTU, por ahora solo tiene la FC0x04 para leer los valores.
ModbusSensor trama de 8 bytes, valor en float, status
crear otro objeto, 'modbusParameter' para leer el parametro y grabarlo, tiene que gestionar valores válidos, formatos float, hex y BCD.
No tengo claro:
¿gestionar otro Arduino?
¿gestionar otro modelo de monitor de energía? de la familia Eastron SDM debe ser fácil.
¿gestionar objetos tipo sensor colgados de un arduino y utilizar el protocolo modbus RTU para pasarlos al modbus master? obliga a crear otro objeto modbusSlave que haga el procedimiento inverso con sensores y estados de circuitos
Es posible optimizar el tiempo de estado receiving utilizando Serial.peek ya que esperamos una trama de un tamaño mínimo. de x bytes,
https://www.arduino.cc/en/Serial/Peek
Definir los problemas para utilizar la librería ModbusSensor.h en un ESP8266-12E.
1º Puerto serie. El ESP-12E parece tener dos puertos, pero uno de ellos está dedicado a la comunicación con el módulo WiFi.
2º Voltaje de referencia. ¿son Suficientes los 3.3V para activa TxEnable?¿son suficientes para el SDM120? ¿es necesario utilizar MAX3485?
I have a problem with Arduino MKR1000 and MKR485 shield.
On the serial monitor I see only 0 for each parameter. What could be the problem?
Si os fijáis los valores de VOLTAGE, CURRENT, POWER, etc, corresponden con el valor de la fase 1 del SDM630.
dos vias:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.