Can’t get Modbus client to connect to slave

I’m doing a project where I simulate some data on two WT32 ETH01 modules and send the data to an rpi where I store it in an SQLite database. I want to setup up a Modbus master on the rpi and have the WT32s as slaves, sending the data to the rpi, with both WT32 connected to an ethernet switch and then the pi connected to that switch with an ethernet cable. As of now, I’m just testing with one WT32 module. When I run the WT32 code, I get the following:

ETH Started
ETH Connected
Configuring Ethernet with IP, Gateway, Subnet Mask, and DNS...
ETH MAC: x:x:x:x:x:x, IPv4: x.x.x.x (not what it actually said of course)
FULL_DUPLEX, 100Mbps
Waiting for Ethernet connection...
WT32-ETH01 IP Address: x.x.x.x
Starting Modbus server...
Modbus server started successfully
Setting up initial time...
Initialization complete.
Battery Percentage: 85
Timestamp: 2024-6-20 21:58:0
Battery Percentage: 85
Timestamp: 2024-6-20 21:58:1
Battery Percentage: 85

But when I run the master code on the pi I get:

2024-06-23 23:10:26,680 - INFO - Database initialized successfully.
2024-06-23 23:10:29,685 - ERROR - Connection to (x.x.x.x, x) failed: timed out (this is the first WT32)
2024-06-23 23:10:29,685 - ERROR - Failed to connect to x.x.x.x, x
2024-06-23 23:10:32,689 - ERROR - Connection to (x.x.x.x, x) failed: timed out (and this is the second)
2024-06-23 23:10:32,689 - ERROR - Failed to connect to x.x.x.x, x
2024-06-23 23:10:32,689 - ERROR - No clients to run.

Yes, I double checked that the Ip addresses of the slaves matches whats in the master code.

I really have no idea why the master can’t receive the data. Can anyone give me any ideas of what might be going wrong here and where I can go from here? I also don’t believe its a firewall issue since I’ve done other IoT projects in the past on the same network. Thanks.

The WT32 code:

#include <WebServer_WT32_ETH01.h>
#include <ModbusIP_ESP8266.h>
#include <time.h>

const int BATTERY_PERCENTAGE = 100;
const int TIMESTAMP_YEAR = 110;
const int TIMESTAMP_MONTH = 111;
const int TIMESTAMP_DAY = 112;
const int TIMESTAMP_HOUR = 113;
const int TIMESTAMP_MINUTE = 114;
const int TIMESTAMP_SECOND = 115;

ModbusIP mb;

IPAddress myIP("ip address of my WT32 module"); // Unique IP for WT32-ETH01
IPAddress myGW("gateway");   // Gateway
IPAddress mySN("subnet");  // Subnet mask
IPAddress myDNS("dns");  // DNS server

void setup() {
  Serial.begin(115200);
  while (!Serial);

  Serial.println("nInitializing...");

  Serial.println("Setting up Modbus Server (Slave) on WT32_ETH01...");
  Serial.print("Starting Modbus Server (Slave) on WT32_ETH01 with ");
  if (!SHIELD_TYPE) {
    Serial.println("Error: SHIELD_TYPE is not defined");
    return;
  }
  Serial.println(SHIELD_TYPE);

  Serial.println("WebServer version: " + String(WEBSERVER_WT32_ETH01_VERSION));

  Serial.println("Setting up WT32_ETH01 event handler...");
  WT32_ETH01_onEvent();

  Serial.println("Initializing Ethernet...");
  if (!ETH.begin(ETH_PHY_TYPE, ETH_PHY_ADDR, ETH_PHY_MDC, ETH_PHY_MDIO, ETH_PHY_POWER, ETH_CLK_MODE)) {
    Serial.println("Error: Failed to initialize Ethernet");
    return;
  }
  
  Serial.println("Configuring Ethernet with IP, Gateway, Subnet Mask, and DNS...");
  if (!ETH.config(myIP, myGW, mySN, myDNS)) {
    Serial.println("Error: Failed to configure Ethernet");
    return;
  }
  
  Serial.println("Waiting for Ethernet connection...");
  WT32_ETH01_waitForConnect();  // Removed the if condition since it doesn't return a value

  Serial.print("WT32-ETH01 IP Address: ");
  Serial.println(ETH.localIP());

  Serial.println("Starting Modbus server...");
  mb.server(); // Start the Modbus server (function does not return a value)
  Serial.println("Modbus server started successfully");

  Serial.println("Setting up initial time...");
  struct tm tm;
  tm.tm_year = 2024 - 1900;
  tm.tm_mon = 5;
  tm.tm_mday = 20;
  tm.tm_hour = 21;
  tm.tm_min = 58;
  tm.tm_sec = 0;
  time_t t = mktime(&tm);
  if (t == -1) {
    Serial.println("Error: Failed to make time");
    return;
  }
  struct timeval now = { .tv_sec = t };
  if (settimeofday(&now, NULL) != 0) {
    Serial.println("Error: Failed to set time of day");
    return;
  }

  Serial.println("Initialization complete.");
}

void loop() {
  if (ETH.linkUp()) {
    mb.task();

    if (mb.isConnected(IPAddress("same as above"))) {
      Serial.println("Master connected");
    }

    int battery_percentage = 85; // example battery percentage

    time_t now;
    struct tm timeinfo;
    if (!getLocalTime(&timeinfo)) {
      Serial.println("Error: Failed to obtain time");
      return;
    }
    time(&now);
    localtime_r(&now, &timeinfo);

    int year = timeinfo.tm_year + 1900;
    int month = timeinfo.tm_mon + 1;
    int day = timeinfo.tm_mday;
    int hour = timeinfo.tm_hour;
    int minute = timeinfo.tm_min;
    int second = timeinfo.tm_sec;

    Serial.print("Battery Percentage: ");
    Serial.println(battery_percentage);
    Serial.print("Timestamp: ");
    Serial.print(year);
    Serial.print("-");
    Serial.print(month);
    Serial.print("-");
    Serial.print(day);
    Serial.print(" ");
    Serial.print(hour);
    Serial.print(":");
    Serial.print(minute);
    Serial.print(":");
    Serial.println(second);

    mb.Hreg(BATTERY_PERCENTAGE, battery_percentage);
    mb.Hreg(TIMESTAMP_YEAR, year);
    mb.Hreg(TIMESTAMP_MONTH, month);
    mb.Hreg(TIMESTAMP_DAY, day);
    mb.Hreg(TIMESTAMP_HOUR, hour);
    mb.Hreg(TIMESTAMP_MINUTE, minute);
    mb.Hreg(TIMESTAMP_SECOND, second);

    delay(1000);
  } else {
    Serial.println("Ethernet not connected");
    delay(1000);
  }
}

The modbus master code on the pi:

import logging
import pymodbus.client as ModbusClient
from pymodbus import ModbusException
import sqlite3
from datetime import datetime

# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')

# Initialize the database and create tables if they don't exist
def init_db():
    try:
        conn = sqlite3.connect('/home/mbus/modbus_project/database/modbus_data.db')
        c = conn.cursor()
        c.execute('''CREATE TABLE IF NOT EXISTS battery_data (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        timestamp TEXT,
                        percentage INTEGER)''')
        c.execute('''CREATE TABLE IF NOT EXISTS power_data (
                        id INTEGER PRIMARY KEY AUTOINCREMENT,
                        timestamp TEXT,
                        power REAL)''')
        conn.commit()
        logging.info("Database initialized successfully.")
    except sqlite3.Error as e:
        logging.error(f"Error initializing database: {e}")
    finally:
        conn.close()

# Store battery data in the database
def store_battery_data(timestamp, percentage):
    try:
        conn = sqlite3.connect('/home/mbus/modbus_project/database/modbus_data.db')
        c = conn.cursor()
        c.execute("INSERT INTO battery_data (timestamp, percentage) VALUES (?, ?)", (timestamp, percentage))
        conn.commit()
        logging.info(f"Battery data stored successfully: {timestamp}, {percentage}%")
    except sqlite3.Error as e:
        logging.error(f"Error storing battery data: {e}")
    finally:
        conn.close()

# Store power data in the database
def store_power_data(timestamp, power):
    try:
        conn = sqlite3.connect('/home/mbus/modbus_project/database/modbus_data.db')
        c = conn.cursor()
        c.execute("INSERT INTO power_data (timestamp, power) VALUES (?, ?)", (timestamp, power))
        conn.commit()
        logging.info(f"Power data stored successfully: {timestamp}, {power} kW")
    except sqlite3.Error as e:
        logging.error(f"Error storing power data: {e}")
    finally:
        conn.close()

# Function to read and store battery data from a Modbus client
def read_and_store_battery(client, slave_id):
    try:
        # Read battery percentage from address 100
        rr = client.read_holding_registers(100, 1, unit=slave_id)
        if rr.isError():
            logging.error(f"Error reading battery percentage: {rr}")
            return
        battery_percentage = rr.registers[0]

        # Read battery timestamp from addresses 110 to 115
        rr = client.read_holding_registers(110, 6, unit=slave_id)
        if rr.isError():
            logging.error(f"Error reading battery timestamp: {rr}")
            return
        year, month, day, hour, minute, second = rr.registers
        battery_timestamp = datetime(year, month, day, hour, minute, second).strftime('%Y-%m-%d %H:%M:%S')

        store_battery_data(battery_timestamp, battery_percentage)
    except ModbusException as e:
        logging.error(f"ModbusException: {e}")

# Function to read and store power data from a Modbus client
def read_and_store_power(client, slave_id):
    try:
        # Read power generation from addresses 200 and 201
        rr = client.read_holding_registers(200, 1, unit=slave_id)
        if rr.isError():
            logging.error(f"Error reading power generation: {rr}")
            return
        power_generation_scaled = rr.registers[0]
        power_generation = power_generation_scaled / 1000.0  # Scaling back to the original floating point value

        # Read power generation timestamp from addresses 210 to 215
        rr = client.read_holding_registers(210, 6, unit=slave_id)
        if rr.isError():
            logging.error(f"Error reading power timestamp: {rr}")
            return
        year, month, day, hour, minute, second = rr.registers
        power_timestamp = datetime(year, month, day, hour, minute, second).strftime('%Y-%m-%d %H:%M:%S')

        store_power_data(power_timestamp, power_generation)
    except ModbusException as e:
        logging.error(f"ModbusException: {e}")

def run_sync_simple_client(clients):
    """Run sync clients for multiple WT32 modules."""
    try:
        while True:
            for client, slave_id, data_type in clients:
                if client.is_socket_open():
                    if data_type == "battery":
                        read_and_store_battery(client, slave_id)
                    elif data_type == "power":
                        read_and_store_power(client, slave_id)
                else:
                    logging.error(f"Connection to {client.host}:{client.port} lost.")
    finally:
        for client, _, _ in clients:
            client.close()

if __name__ == "__main__":
    # Initialize the database
    init_db()

    # Define the WT32 modules (IP address, port, slave ID, and data type)
    wt32_modules = [
        ("xxx.xxx.xxx.xxx", 502, 1, "battery"),  # WT32 module for battery data
        ("xxx.xxx.xxx.xxx", 502, 2, "power")    # WT32 module for power data
    ]

    # Create Modbus clients
    clients = []
    for ip, port, slave_id, data_type in wt32_modules:
        client = ModbusClient.ModbusTcpClient(ip, port=port)
        if client.connect():
            clients.append((client, slave_id, data_type))
            logging.info(f"Connected to {ip}:{port}")
        else:
            logging.error(f"Failed to connect to {ip}:{port}")

    # Run the Modbus clients
    if clients:
        run_sync_simple_client(clients)
    else:
        logging.error("No clients to run.")

I tried to ping the WT32 module from the pi and it just spit out “host unreachable”.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật