Python Forum
Pymodbus read and save to database
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Pymodbus read and save to database
#1
Hello,

in our company we will install multiple energy meters (abb m4m ethernet 20). This energy meter works via modbus tcp/ip.

I have a working python script for reading registers but i would like to know how can i save values to mysql database? I want to save each measurement for every meter (we will have 25 of them).

Also if anyone has any better code for reading values from all the meters at once please tell me.

DB table - meter:
measurement_id  
meter - name of meter (M01, M02,...)
power 
energy 
date_of_reading
Current code:
import mysql.connector
from pymodbus.client import ModbusTcpClient
from datetime import datetime

mydb = mysql.connector.connect(
  host="192.168.25.2",
  user="xxxx",
  password="xxxx",
  database="energetics"
)

mycursor = mydb.cursor()

M01 = '192.168.30.156' #LOCATION 1
M02 = '192.168.22.95' #LOCATION 2

ips = [M01, M02]

date_of_reading = datetime.now()

meters = []

for ip in ips:
    meters.append(ModbusTcpClient(ip))

    power_register = []
    energy_register = []

for meter in meters:
    power_register.append(meter.read_holding_registers(23322, 2))
    energy_register.append(meter.read_holding_registers(20480, 4))

    power_calculation = []
    energy_calculation = []

for i in range(len(meters)):
    power_calculation.append(round(((power_register[i].registers[0] * pow(2, 16) + power_register[i].registers[1]) * 0.01 / 1000), 2))
    energy_calculation.append(round(((energy_register[i].registers[2] * pow(2, 16) + energy_register[i].registers[3]) * 0.01), 2))

for i in range(len(meters)):
	sql = ("INSERT INTO meter (meter, power, energy, date_of_reading) VALUES (%s, %s, %s, %s)",
    (meters[i], power_calculation[i], energy_calculation[i], date_of_reading))

mycursor.execute(*sql)

mydb.commit()

print("Success !")

mycursor.close()
This is the code but it works only until part where i want to save to sql.
Reply
#2
[removed].

Sorry, I'm wrong, but you may want to do a so-called 'print debug': print(*sql) before the execute, so that you can see how it will be iterated by the *sql
Sig:
>>> import this

The UNIX philosophy: "Do one thing, and do it well."

"The danger of computers becoming like humans is not as great as the danger of humans becoming like computers." :~ Konrad Zuse

"Everything should be made as simple as possible, but not simpler." :~ Albert Einstein
Reply
#3
for i in range(len(meters)):
    sql = ("INSERT INTO meter (meter, power, energy, date_of_reading) VALUES (%s, %s, %s, %s)",
    (meters[i], power_calculation[i], energy_calculation[i], date_of_reading))
 
mycursor.execute(*sql)
This will insert just the values for the last meter. You either move the execute inside the loop, or look at changing your code to using executemany
Something like this (code not tested):

import mysql.connector
from pymodbus.client import ModbusTcpClient
from datetime import datetime

 
M01 = '192.168.30.156' #LOCATION 1
M02 = '192.168.22.95' #LOCATION 2
 
ips = [M01, M02]
 
date_of_reading = datetime.now()
meters = [ModbusTcpClient(ip) for ip in ips]
readings = []
 
for meter in meters:
    power_register = meter.read_holding_registers(23322, 2)
    energy_register = meter.read_holding_registers(20480, 4)
    power_calculation = round((power_register.registers[0] * pow(2, 16) + power_register.registers[1]) * 0.01 / 1000, 2)
    energy_calculation = round((energy_register.registers[2] * pow(2, 16) + energy_register.registers[3]) * 0.01, 2)
    reading = meter, power_calculation, energy_calculation, date_of_reading
    readings.append(reading)
 
sql = "INSERT INTO meter (meter, power, energy, date_of_reading) VALUES (%s, %s, %s, %s)"

mydb = mysql.connector.connect(
  host="192.168.25.2",
  user="xxxx",
  password="xxxx",
  database="energetics"
)
 
mycursor = mydb.cursor()
mycursor.executemany(sql, readings)
mydb.commit()
mycursor.close()

print("Success !")
From here you can improve the code - using e.g. named tuple for readings, make your code use functions and/or OOP, etc.
If you can't explain it to a six year old, you don't understand it yourself, Albert Einstein
How to Ask Questions The Smart Way: link and another link
Create MCV example
Debug small programs

Reply
#4
(Mar-02-2023, 09:14 AM)buran Wrote:
for i in range(len(meters)):
    sql = ("INSERT INTO meter (meter, power, energy, date_of_reading) VALUES (%s, %s, %s, %s)",
    (meters[i], power_calculation[i], energy_calculation[i], date_of_reading))
 
mycursor.execute(*sql)
This will insert just the values for the last meter. You either move the execute inside the loop, or look at changing your code to using executemany
Something like this (code not tested):

import mysql.connector
from pymodbus.client import ModbusTcpClient
from datetime import datetime

 
M01 = '192.168.30.156' #LOCATION 1
M02 = '192.168.22.95' #LOCATION 2
 
ips = [M01, M02]
 
date_of_reading = datetime.now()
meters = [ModbusTcpClient(ip) for ip in ips]
readings = []
 
for meter in meters:
    power_register = meter.read_holding_registers(23322, 2)
    energy_register = meter.read_holding_registers(20480, 4)
    power_calculation = round((power_register.registers[0] * pow(2, 16) + power_register.registers[1]) * 0.01 / 1000, 2)
    energy_calculation = round((energy_register.registers[2] * pow(2, 16) + energy_register.registers[3]) * 0.01, 2)
    reading = meter, power_calculation, energy_calculation, date_of_reading
    readings.append(reading)
 
sql = "INSERT INTO meter (meter, power, energy, date_of_reading) VALUES (%s, %s, %s, %s)"

mydb = mysql.connector.connect(
  host="192.168.25.2",
  user="xxxx",
  password="xxxx",
  database="energetics"
)
 
mycursor = mydb.cursor()
mycursor.executemany(sql, readings)
mydb.commit()
mycursor.close()

print("Success !")
From here you can improve the code - using e.g. named tuple for readings, make your code use functions and/or OOP, etc.

Thank you for this, i've test it and it's working ! This is my first time with modbus and python and i'm not familiar with functions and OOP but i will try to implement them... i'm learning slowly Smile
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Problem with pymodbus - ModuleNotFoundError: No module named 'pymodbus.client.sync' stsxbel 2 23,712 Nov-02-2023, 08:20 AM
Last Post: South_east
  how to save to multiple locations during save cubangt 1 554 Oct-23-2023, 10:16 PM
Last Post: deanhystad
  Pymodbus Write value to register stsxbel 10 8,171 Aug-18-2022, 01:42 PM
Last Post: DeaD_EyE
  Read JSON via API and write to SQL database TecInfo 5 2,207 Aug-09-2022, 04:44 PM
Last Post: TecInfo
  How to save specific variable in for loop in to the database? ilknurg 1 1,147 Mar-09-2022, 10:32 PM
Last Post: cubangt
  SaltStack: MySQL returner save less data into Database table columns xtc14 2 2,165 Jul-02-2021, 02:19 PM
Last Post: xtc14
  Looping to read data in database CEC68 1 1,711 Sep-24-2020, 08:54 PM
Last Post: scidam
  sqlite3 database does not save data across restarting the program SheeppOSU 1 3,451 Jul-24-2020, 05:53 AM
Last Post: SheeppOSU
  Read and save file in chucksize zinho 3 2,466 Apr-02-2020, 08:12 AM
Last Post: DeaD_EyE
  Save a file uploaded from client-side without having to read into memory andym118 3 5,066 Nov-21-2019, 07:34 AM
Last Post: DeaD_EyE

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020