├── README.md ├── modbus-mqtt_client.py ├── modbus_server.py └── mqtt_remote_client.py /README.md: -------------------------------------------------------------------------------- 1 | # modbus-mqtt 2 | ## Python implementation of Modbus TCP + MQTT. Data can be written to/read from multiple MODBUS slave devices from a remote MQTT client.

3 | 4 | This code includes a **reg_config** option which allows the end user to select the registers to be used while writing and reading data.
5 | This code also includes a **slave_config** option which allows the end user to assign slave IDs to existing devices or add new devices with their own slave ID.
6 | **Data read/write** to these slaves can be done from a remote MQTT client connected to an [online MQTT server](https://test.mosquitto.org/).
7 | *Hence this implementation allows for the use of multiple MODBUS TCP slaves whose slave IDs can be changed or new slaves added and register number to be used for each slave can also be configured by the user. Data read/write can be done from a remote client. Usage is as explained below.*

8 | 9 | The implementation consists of 3 inter-dependent programs :

10 | 11 | 1) modbus_server.py - The pymodbus Modbus TCP server which reads/writes modbus data from slaves.

12 | 13 | 2) modbus-mqtt_client.py - This is a pymodbus Modbus TCP client and a paho-mqtt MQTT client which receives requests (read/write) from remote MQTT client from the MQTT broker and sends requests (read/write) to the modbus server. If it is a read function, it sends the read data back to remote client through the MQTT broker.

14 | 15 | 3) mqtt_remote_client.py - This is the user end from where requests are sent to read/write slave data into respective topics n MQTT broker and this is received by modbus-mqtt_client which is subscribed to the those topics.

16 | 17 | Applications :

18 | The code is a general implementation of Modbus TCP and MQTT which can be modified and used for various IoT applications.
19 | An example would bean energy monitoring system for a home or office. To do this, one could run modbus_server.py and modbus-mqtt_client.py on a Raspberry Pi connected to one or more slave Modbus sensors. The data of the sensors can be accesed remotely by running mqtt_remote_client.py (with slight changes to read data at regular time intervals) on a remote personal computer and an [IoT Dashboard](https://thingsboard.io/) can be used to visualise the data.
20 | Various applications like this can be implemented with slight adjustments to the code. 21 | -------------------------------------------------------------------------------- /modbus-mqtt_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Python implementation of Modbus TCP + MQTT. Data can be read/written from remote MQTT client into MODBUS slave. 4 | 5 | This code includes a REGISTER CONFIG option which allows the end user to select the registers to be used while writing and reading data. 6 | reg_config is a topic on the mqtt server and is updated every time it is changed. Existing devices register number can be changed or new devices can be added and data written into that register. 7 | 8 | This code also includes a SLAVE CONFIG option which allows the end user to assign slave IDs to devices or add new devices with their own slave ID. 9 | slave_config is a topic on the mqtt server and is updated every time it is changed. Existing devices slave/unit ID can be changed or new devices can be added. 10 | 11 | Hence this implementation allows for the use of multiple MODBUS TCP slaves whose slave IDs can be changed or new slaves added and register number to be used 12 | for each slave can also be configured by the user. Data can be read/written to these slaves from a remote MQTT client connected to iot.eclipse.org MQTT server. 13 | ''' 14 | 15 | #importing all required methods from pymodbus for estalishing MODBUS TCP connection 16 | import serial 17 | import socket 18 | import traceback 19 | from pymodbus.framer.rtu_framer import ModbusRtuFramer 20 | from pymodbus.constants import Endian 21 | from pymodbus.payload import BinaryPayloadDecoder 22 | from pymodbus.constants import Defaults 23 | from pymodbus.utilities import hexlify_packets 24 | from pymodbus.factory import ServerDecoder 25 | from pymodbus.datastore import ModbusServerContext 26 | from pymodbus.device import ModbusControlBlock 27 | from pymodbus.device import ModbusDeviceIdentification 28 | from pymodbus.transaction import * 29 | from pymodbus.exceptions import NotImplementedException, NoSuchSlaveException 30 | from pymodbus.pdu import ModbusExceptions as merror 31 | from pymodbus.compat import socketserver, byte2int 32 | from binascii import b2a_hex 33 | from pymodbus.server.sync import StartTcpServer 34 | from pymodbus.server.sync import ModbusTcpServer 35 | from pymodbus.server.sync import StartUdpServer 36 | from pymodbus.server.sync import StartSerialServer 37 | import pymodbus.server.sync 38 | from pymodbus.server.sync import ModbusConnectedRequestHandler 39 | from pymodbus.device import ModbusDeviceIdentification 40 | from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock 41 | from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext 42 | from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer 43 | from pymodbus.client.sync import ModbusTcpClient as ModbusClient 44 | 45 | import paho.mqtt.client as mqtt #import the client1 46 | import time #for time delays 47 | 48 | import logging 49 | import json #to convert reg_config and slave_config from received json format 50 | 51 | reg_config = {} #global variale to store reg_config as it is updated by remote mqtt client1 52 | slave_config = {} #global variable to store slave_config as it is updated by remote mqtt client1 53 | device_in_use = '' #global variable which stores the name of device currently being accessed by remote mqtt client1 54 | 55 | 56 | #-----------------------------------------------------------------------------------------------------------------------------------------------------------# 57 | # device_in_use variable has the key(name) of the device which is currently being accessed. This is set when data is written when user selects the device. 58 | # This method updates the device_in_use variable when a new device is accessed. 59 | #-----------------------------------------------------------------------------------------------------------------------------------------------------------# 60 | def device_in_use_on_message(client, userdata, message): 61 | global device_in_use #to specifiy that the global variable is being referenced. 62 | device_in_use = message.payload 63 | print("Device in use ",device_in_use) 64 | 65 | 66 | #-------------------------------------------------------------------------------------------------------------------------------------------------------------# 67 | # This method is called when data is written into a device. It first finds the device name from device_in_use which was updated in device_in_use_on_message(). 68 | # Then it uses reg_config and slave_config and finds corresponding register number and slave ID respectively. 69 | # Finally it writes the data received into that register and slave ID of the MODBUS device by establishing a connection with the MODBUS server. 70 | #-------------------------------------------------------------------------------------------------------------------------------------------------------------# 71 | def data_on_message(client, userdata, message): 72 | global device_in_use 73 | diu1 = device_in_use.decode("utf-8") #to convert from binary array to string 74 | topic = message.topic 75 | value = int(message.payload) #Converting the bytearray to integer value. 76 | print('Data received.') 77 | print('Value :',value) 78 | reg = int(reg_config[locals()['diu1']]) 79 | UNIT = int(slave_config[locals()['diu1']]) 80 | print("Register to write into :\n") 81 | print(reg) 82 | print("Slave unit to write into :\n") 83 | print(UNIT) 84 | mclient = ModbusClient(host = "localhost", port = 502, framer = ModbusRtuFramer) #Initialise the ModbusTcpClient 85 | mclient.connect() 86 | rw = mclient.write_register(reg,value,unit=UNIT) 87 | mclient.close() 88 | 89 | #----------------------------------------------------------------------------------------------------------# 90 | # This method updates reg_config global variable when the reg_config is updated by remote mqtt client1 91 | # so that data_on_message and read_req_on_message read and write from correct register. 92 | #----------------------------------------------------------------------------------------------------------# 93 | def reg_config_on_message(client, userdata, message): 94 | print("reg_config received\n") 95 | global reg_config #referring to global variable reg_config. 96 | reg_config = json.loads(message.payload) #converting from json data 97 | print(reg_config) 98 | 99 | 100 | #----------------------------------------------------------------------------------------------------------# 101 | # This method updates slave_config global variable when the slave_config is updated by remote mqtt client1 102 | # so that data_on_message and read_req_on_message read and write from correct slave unit. 103 | #----------------------------------------------------------------------------------------------------------# 104 | def slave_config_on_message(client,userdata,message): 105 | print("slave_config received") 106 | global slave_config #referring to global variable slave_config. 107 | slave_config = json.loads(message.payload) #converting from json data 108 | print(slave_config) 109 | 110 | #---------------------------------------------------------------------------------------------------------------------------------------------------# 111 | # This method is called when data read request is sent from remote mqtt client1. 112 | # It finds the register number and slave ID of that device (device name is sent as payload of the request message) from reg_config and slave_config. 113 | # Then it establishes a MODBUS TCP link and reads the value. Read value is published to data_req which is received by remote client. 114 | #---------------------------------------------------------------------------------------------------------------------------------------------------# 115 | 116 | 117 | #Method to call when requested data is published. Used as a confirmation that data has been published. 118 | def data_req_on_publish(client, userdata, mid): 119 | print("Data request published\n") 120 | 121 | def req_response_on_connect(client, userdata, flags, rc): 122 | print("Connection established.") 123 | 124 | def read_req_on_message(client,userdata,message): 125 | print("Data read request received") 126 | diu1 = message.payload.decode("utf-8") 127 | print("Reading data from ",diu1) 128 | reg = int(reg_config[locals()['diu1']]) 129 | UNIT = int(slave_config[locals()['diu1']]) 130 | mclient = ModbusClient(host = "localhost", port = 502, framer = ModbusRtuFramer) #Initialise the ModbusTcpClient 131 | mclient.connect() 132 | rr = mclient.read_holding_registers(reg,1,unit=UNIT) 133 | value = rr.registers 134 | print(value) 135 | client.publish('data_req',value[0],qos=2) #published to data_req to which user client is subscribed. 136 | #--------------------------------------------------------------------------- # 137 | # configure the service logging 138 | # --------------------------------------------------------------------------- # 139 | FORMAT = ('%(asctime)-15s %(threadName)-15s' 140 | ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') 141 | logging.basicConfig(format=FORMAT) 142 | log = logging.getLogger() 143 | log.setLevel(logging.DEBUG) 144 | 145 | broker_address = "test.mosquitto.org" #Using online mqtt broker 146 | 147 | #------------------------------------------------------------------------------------------------------------# 148 | # Creating reg_config instance. This instance subscribes to and hence receives data from topic reg_config. 149 | # Any changes made in reg_config by user and uploaded here and received by this client. 150 | # Once received, reg_config global variable is updated. 151 | #------------------------------------------------------------------------------------------------------------# 152 | print("creating reg_config instance") 153 | client_reg = mqtt.Client("REG") 154 | client_reg.on_message = reg_config_on_message 155 | print("connecting to broker") 156 | client_reg.connect(broker_address) 157 | client_reg.loop_start() 158 | print("Subscribing to reg_config") 159 | client_reg.subscribe('reg_config',qos=2) 160 | 161 | #------------------------------------------------------------------------------------------------------------# 162 | # Creating slave_config instance. This instance subscribes to and hence receives data from topic slave_config. 163 | # Any changes made in slave_config by user and uploaded to this topic and received by this client. 164 | # Once received, slave_config global variable is updated. 165 | #------------------------------------------------------------------------------------------------------------# 166 | print("creating slave_config instance") 167 | client_slave = mqtt.Client("SLAVE") 168 | client_slave.on_message = slave_config_on_message 169 | print("connecting to broker") 170 | client_slave.connect(broker_address) 171 | client_slave.loop_start() 172 | print("Subscribing to slave_config") 173 | client_slave.subscribe('slave_config',qos=2) 174 | 175 | #--------------------------------------------------------------------------------------------------------------------------------------------------------------------------# 176 | # Creating device is use instance. This instance subscribes to and hence receives data from topic device_in_use. 177 | # Whenever a request is send by the user to read/write from a slave, the name of the slave which has been reqested is updated on this topic and received by this client. 178 | # Once received, device_in_use global variable is updated. 179 | #--------------------------------------------------------------------------------------------------------------------------------------------------------------------------# 180 | print("Creating device_in_use instance") 181 | client_diu = mqtt.Client("DIU") 182 | client_diu.on_message = device_in_use_on_message 183 | print("connecting to broker") 184 | client_diu.connect(broker_address) 185 | client_diu.loop_start() 186 | print("Subscribing to device_in_use") 187 | client_diu.subscribe('device_in_use',qos=2) 188 | 189 | #----------------------------------------------------------------------------------------------------------------------------------------------# 190 | # Creating data instance. This instance subscribes and hence receives data from topic data. 191 | # Whenever data to write into a slave is sent by the user, it is updated on this topic and received by this client. 192 | # Once received, it is written into the register specified by reg_config of that slave and slave unit specified by slave_config in function data_on_message. 193 | #----------------------------------------------------------------------------------------------------------------------------------------------# 194 | print("Creating data instance") 195 | client_data = mqtt.Client("DATA") 196 | client_data.on_message = data_on_message 197 | print("connecting to broker") 198 | client_data.connect(broker_address) 199 | client_data.loop_start() 200 | print("Subscribing to data") 201 | client_data.subscribe('data',qos=2) 202 | 203 | 204 | #-----------------------------------------------------------------------------------------------------------------------------------------------------# 205 | # Creating data request instance. This instance subscribes and hence recieves data from topic read_req. 206 | # Wheber data is to be read from a slave, the name of the slave to read data from is updated on this topic and hence received by this client. 207 | # Once received, it is read from register specified by reg_config of that slave and published to be received by user in method read_req_on_message. 208 | #-----------------------------------------------------------------------------------------------------------------------------------------------------# 209 | print("Creating data req instance") 210 | client_data_req = mqtt.Client("DATA_REQ") 211 | client_data_req.on_message = read_req_on_message 212 | client_data_req.on_publish = data_req_on_publish 213 | print("connecting to broker") 214 | client_data_req.connect(broker_address) 215 | client_data_req.loop_start() 216 | print("Subscribing to read req") 217 | client_data_req.subscribe('read_req',qos=2) 218 | 219 | 220 | time.sleep(100000) #time delay to keep this client online, running and waiting for requests. Can be manually shut down. 221 | 222 | #stop loops and disconnect all clients 223 | client_reg.loop_stop() 224 | client_slave.loop_stop() 225 | client_diu.loop_stop() 226 | client_data.loop_stop() 227 | client_data_req.loop_stop() 228 | client_reg.disconnect() 229 | client_slave.disconnect() 230 | client_diu.disconnect() 231 | client_data.disconnect() 232 | client_data_req.disconnect() 233 | -------------------------------------------------------------------------------- /modbus_server.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | """ 3 | Pymodbus implementation of Modbus TCP client-server. Read from holding registers and write the data to other holding registers. 4 | Server - Local Pymodbus TCP server 5 | Client - Pymodbus TCP client 6 | 7 | """ 8 | from threading import Timer 9 | 10 | from pymodbus.server.sync import StartTcpServer 11 | from pymodbus.server.sync import ModbusTcpServer 12 | from pymodbus.server.sync import StartUdpServer 13 | from pymodbus.server.sync import StartSerialServer 14 | 15 | from pymodbus.device import ModbusDeviceIdentification 16 | from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock 17 | from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext 18 | 19 | from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer 20 | from pymodbus.client.sync import ModbusTcpClient as ModbusClient 21 | 22 | # --------------------------------------------------------------------------- # 23 | # configure the service logging 24 | # --------------------------------------------------------------------------- # 25 | import logging 26 | FORMAT = ('%(asctime)-15s %(threadName)-15s' 27 | ' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s') 28 | logging.basicConfig(format=FORMAT) 29 | log = logging.getLogger() 30 | log.setLevel(logging.DEBUG) 31 | 32 | # ----------------------------------------------------------------------- # 33 | # initialize your data store 34 | # ----------------------------------------------------------------------- # 35 | # The datastores only respond to the addresses that they are initialized to 36 | # Therefore, if you initialize a DataBlock to addresses of 0x00 to 0xFF, a 37 | # request to 0x100 will respond with an invalid address exception. This is 38 | # because many devices exhibit this kind of behavior (but not all):: 39 | # 40 | # block = ModbusSequentialDataBlock(0x00, [0]*0xff) 41 | # 42 | # Continuing, you can choose to use a sequential or a sparse DataBlock in 43 | # your data context. The difference is that the sequential has no gaps in 44 | # the data while the sparse can. Once again, there are devices that exhibit 45 | # both forms of behavior:: 46 | # 47 | # block = ModbusSparseDataBlock({0x00: 0, 0x05: 1}) 48 | # block = ModbusSequentialDataBlock(0x00, [0]*5) 49 | # 50 | # Alternately, you can use the factory methods to initialize the DataBlocks 51 | # or simply do not pass them to have them initialized to 0x00 on the full 52 | # address range:: 53 | # 54 | # store = ModbusSlaveContext(di = ModbusSequentialDataBlock.create()) 55 | # store = ModbusSlaveContext() 56 | # 57 | # Finally, you are allowed to use the same DataBlock reference for every 58 | # table or you may use a separate DataBlock for each table. 59 | # This depends if you would like functions to be able to access and modify 60 | # the same data or not:: 61 | # 62 | # block = ModbusSequentialDataBlock(0x00, [0]*0xff) 63 | # store = ModbusSlaveContext(di=block, co=block, hr=block, ir=block) 64 | # 65 | # The server then makes use of a server context that allows the server to 66 | # respond with different slave contexts for different unit ids. By default 67 | # it will return the same context for every unit id supplied (broadcast 68 | # mode). 69 | # However, this can be overloaded by setting the single flag to False and 70 | # then supplying a dictionary of unit id to context mapping:: 71 | # 72 | # slaves = { 73 | # 0x01: ModbusSlaveContext(...), 74 | # 0x02: ModbusSlaveContext(...), 75 | # 0x03: ModbusSlaveContext(...), 76 | # } 77 | # context = ModbusServerContext(slaves=slaves, single=False) 78 | # 79 | # The slave context can also be initialized in zero_mode which means that a 80 | # request to address(0-7) will map to the address (0-7). The default is 81 | # False which is based on section 4.4 of the specification, so address(0-7) 82 | # will map to (1-8):: 83 | # 84 | # store = ModbusSlaveContext(..., zero_mode=True) 85 | # ----------------------------------------------------------------------- # 86 | store = ModbusSlaveContext( 87 | di=ModbusSequentialDataBlock(0, [17]*100), 88 | co=ModbusSequentialDataBlock(0, [17]*100), 89 | hr=ModbusSequentialDataBlock(0, [17]*100), 90 | ir=ModbusSequentialDataBlock(0, [17]*100)) 91 | 92 | # ----------------------------------------------------------------------- # 93 | # initialize the server information 94 | # ----------------------------------------------------------------------- # 95 | # If you don't set this or any fields, they are defaulted to empty strings. 96 | # ----------------------------------------------------------------------- # 97 | context = ModbusServerContext(slaves=store, single=True) 98 | identity = ModbusDeviceIdentification() 99 | identity.VendorName = 'Pymodbus' 100 | identity.ProductCode = 'PM' 101 | identity.VendorUrl = 'http://github.com/riptideio/pymodbus/' 102 | identity.ProductName = 'Pymodbus Server' 103 | identity.ModelName = 'Pymodbus Server' 104 | identity.MajorMinorRevision = '2.2.0' 105 | 106 | # ----------------------------------------------------------------------- # 107 | # run the server you want 108 | # ----------------------------------------------------------------------- # 109 | # Tcp: 110 | StartTcpServer(context, identity=identity, address=("localhost", 502), framer = ModbusRtuFramer) 111 | 112 | 113 | -------------------------------------------------------------------------------- /mqtt_remote_client.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Python implementation of Modbus TCP + MQTT. Data can be read/written from remote MQTT client into MODBUS slave. 4 | 5 | This code includes a REGISTER CONFIG option which allows the end user to select the registers to be used while writing and reading data. 6 | reg_config is a topic on the mqtt server and is updated every time it is changed. Existing devices register number can be changed or new devices can be added and data written into that register. 7 | 8 | This code also includes a SLAVE CONFIG option which allows the end user to assign slave IDs to devices or add new devices with their own slave ID. 9 | slave_config is a topic on the mqtt server and is updated every time it is changed. Existing devices slave/unit ID can be changed or new devices can be added. 10 | 11 | Hence this implementation allows for the use of multiple MODBUS TCP slaves whose slave IDs can be changed or new slaves added and register number to be used 12 | for each slave can also be configured by the user. Data can be read/written to these slaves from a remote MQTT client connected to iot.eclipse.org MQTT server. 13 | ''' 14 | import paho.mqtt.client as mqtt 15 | import time 16 | import json 17 | 18 | #--------------------------------------------------------------------------------------------------------------------------------# 19 | # reg_config dict includes some standard devices register configuration which can be changed or new devices can be added. 20 | #--------------------------------------------------------------------------------------------------------------------------------# 21 | reg_config={"energy_meter": '01',"temp_sensor":'05'} 22 | 23 | #------------------------------------------------------------------------------------------------------------# 24 | # slave_config has a list of devices and their slave IDs which can be changed or new devices can be added. 25 | #------------------------------------------------------------------------------------------------------------# 26 | slave_config={"energy_meter":'01',"temp_sensor":'02'} 27 | 28 | read_req_value = 0 #to store response of read_req. 29 | 30 | #method to display a message once the user(client1) has connected to mqtt server. Called when connection is succesful. 31 | def on_connect(client, userdata, flags, rc): 32 | print("Connected flags"+str(flags)+"result code "\ 33 | +str(rc)+"client1_id ") 34 | client.connected_flag=True 35 | 36 | #method to display a message when the data has been published by user client (client1). Called when publish is succesful. 37 | def on_publish(client, userdata, mid): 38 | print("Data published.") 39 | 40 | #method to print the data received from the register after sending a read request. 41 | def data_req_on_message(client,userdata,message): 42 | print("Data received :\n") 43 | read_req_value = int(message.payload) 44 | print("Register value :\n") 45 | print(read_req_value) 46 | 47 | broker_address="test.mosquitto.org" #Using online broker 48 | 49 | #-------------------------------------------------------------------------------------------------------------------------------------------------------# 50 | # Creating instance client1. This client is the end user which will send requests to read/write data from modbus tcp slaves and can be a remote client. 51 | # The requests from client1 are sent to the MQTT server. Client2 receives the requsts, reg and slave config from the respective topics on MQTT server. 52 | # Client2 is both an MQTT client and MODBUS client. It sends the received request to the MODBUS server to cread/write data from the slaves. 53 | #--------------------------------------------------------------------------------------------------------------------------------------------------------# 54 | print("creating new instance") 55 | client1 = mqtt.Client("P1") 56 | client1.on_publish = on_publish 57 | client1.on_message = data_req_on_message 58 | print("connecting to broker") 59 | client1.connect(broker_address) #connect to broker 60 | client1.loop_start() #start the loop 61 | 62 | print("Pushing reg_config") 63 | client1.publish('reg_config',json.dumps(reg_config),qos=2) #Pushing initial reg_config 64 | time.sleep(2) #delay to wait till reg_config is pushed before prompting for data input 65 | 66 | print("Pushing slave_config") 67 | client1.publish('slave_config',json.dumps(slave_config),qos=2) #Pushing initial slave_config 68 | time.sleep(2) #delay to wait till slave_config is pushed before prompting for data input 69 | 70 | print("Subscribing to data request") 71 | client1.subscribe('data_req',qos=0) #Subscribing to data request topic where the requested data from register is published by client2. 72 | time.sleep(2) 73 | 74 | cont = 'Y' #loop control variable 75 | while cont == 'Y': 76 | choice = input('1)data_write\n2)data_read\n3)reg_config\n4)slave_config\n') 77 | if choice == '3': 78 | print(reg_config) 79 | choice = input('1)Change existing\n2)Add new\n3)Exit\n') 80 | if choice == '1': 81 | device = input("Enter device\n") 82 | new_value = input("Enter new register number\n") 83 | reg_config[locals()['device']] = new_value #Updating reg_config dict. key is given using locals() function which returns all local variables. locals()['device'] will return the string which is stored in variable name 'device' 84 | elif choice == '2': 85 | device = input("Enter new device\n") 86 | value = input("Enter register number\n") 87 | reg_config[locals()['device']] = value #Updating reg_config dict. key is given using locals() function which returns all local variables. locals()['device'] will return the string which is stored in variable name 'device' 88 | elif choice == '3': 89 | continue 90 | else: 91 | print("Invalid choice\n") 92 | continue 93 | print("new reg_config:\n") 94 | print(reg_config) 95 | print("Pushing reg_config\n") 96 | client1.publish('reg_config',json.dumps(reg_config),qos=2) 97 | time.sleep(3) 98 | elif choice == '4': 99 | print(slave_config) 100 | choice = input('1)Change existing\n2)Add new\n3)Exit\n') 101 | if choice == '1': 102 | device = input("Enter device\n") 103 | new_value = input("Enter new slave ID\n") 104 | slave_config[locals()['device']] = new_value #Updating slave_config dict. key is given using locals() function which returns all local variables. locals()['device'] will return the string which is stored in variable name 'device' 105 | elif choice == '2': 106 | device = input("Enter new device\n") 107 | value = input("Enter slave ID\n") 108 | slave_config[locals()['device']] = value #Updating slave_config dict. key is given using locals() function which returns all local variables. locals()['device'] will return the string which is stored in variable name 'device' 109 | value = input("Enter register config of new device\n") 110 | reg_config[locals()['device']] = value 111 | elif choice == '3': 112 | continue 113 | else: 114 | print("Invalid choice\n") 115 | continue 116 | print("new slave_config:\n") 117 | print(slave_config) 118 | print("new reg_config:\n") 119 | print(reg_config) 120 | print("Pushing slave_config and reg_config\n") 121 | client1.publish('slave_config',json.dumps(slave_config),qos=2) 122 | time.sleep(2) 123 | client1.publish('reg_config',json.dumps(reg_config),qos=2) 124 | time.sleep(2) 125 | elif choice == '1': 126 | device = input("Select device to which data is to be pushed:\n") 127 | value = int(input("Enter value(in decimal) to put in register :\n")) 128 | try: 129 | UNIT = int(slave_config[locals()['device']]) #Checking if entered device has been added as a slave. 130 | except: 131 | print("Device does not exist in database. Please add the device to slave_config or select existing device.") 132 | continue 133 | print("Pushing value to device\n",device) 134 | client1.publish('device_in_use',device,qos=0) #publish the device currently in use. the register number of tht device is taken from reg_config and value is written. 135 | client1.publish('data',value,qos=0) #publish value to be put in register 136 | time.sleep(2) 137 | elif choice == '2': 138 | device = input("Select device from which data is to be read:\n") 139 | try: 140 | UNIT = int(slave_config[locals()['device']]) #Checking if entered device has been added as a slave. 141 | except: 142 | print("Device does not exist in database. Please add device to slave_config or select existing device.") 143 | continue 144 | client1.publish('read_req',device,qos=0) 145 | time.sleep(5) 146 | else: 147 | print("Invalid choice") 148 | cont = input("Continue? [Y/N]\n") 149 | time.sleep(4) 150 | client1.loop_stop() --------------------------------------------------------------------------------