@@ -73,7 +73,7 @@ def connect_modbus():
7373 def add_cors_headers (response ):
7474 """Add CORS headers to allow cross-origin requests"""
7575 response .headers ['Access-Control-Allow-Origin' ] = '*'
76- response .headers ['Access-Control-Allow-Methods' ] = 'GET, POST, OPTIONS'
76+ response .headers ['Access-Control-Allow-Methods' ] = 'GET, POST, PUT, OPTIONS'
7777 response .headers ['Access-Control-Allow-Headers' ] = 'Content-Type'
7878 return response
7979
@@ -101,7 +101,7 @@ def get_status():
101101 def read_coil (address ):
102102 """Read single coil"""
103103 unit = request .args .get ('unit' , default = 1 , type = int )
104- result = modbus_client .read_coils (address , 1 , unit )
104+ result = modbus_client .read_coils (address , 1 , unit = unit )
105105
106106 if result is None :
107107 return jsonify ({'error' : 'Failed to read coil' }), 500
@@ -117,7 +117,7 @@ def read_coil(address):
117117 def read_coils (address , count ):
118118 """Read multiple coils"""
119119 unit = request .args .get ('unit' , default = 1 , type = int )
120- result = modbus_client .read_coils (address , count , unit )
120+ result = modbus_client .read_coils (address , count , unit = unit )
121121
122122 if result is None :
123123 return jsonify ({'error' : 'Failed to read coils' }), 500
@@ -130,7 +130,7 @@ def read_coils(address, count):
130130 'unit' : unit
131131 })
132132
133- @app .route ('/api/coils/<int:address>' , methods = ['POST' ])
133+ @app .route ('/api/coils/<int:address>' , methods = ['POST' , 'PUT' ])
134134 def write_coil (address ):
135135 """Write single coil"""
136136 data = request .get_json ()
@@ -172,30 +172,47 @@ def toggle_coil(address):
172172 # Read current state
173173 result = modbus_client .read_coils (address , 1 , unit = unit )
174174 if result is None :
175- return jsonify ({'error' : 'Failed to read coil' }), 500
175+ return jsonify ({'error' : f 'Failed to read coil { address } ' }), 500
176176
177- # Toggle state
178- current_state = result [0 ]
179- new_state = not current_state
177+ # Toggle value
178+ current_value = result [0 ]
179+ new_value = not current_value
180180
181- if modbus_client .write_coil (address , new_state , unit = unit ):
181+ # Write new value
182+ if modbus_client .write_coil (address , new_value , unit = unit ):
182183 return jsonify ({
183184 'success' : True ,
184185 'address' : address ,
185- 'previous ' : current_state ,
186- 'current ' : new_state ,
187- 'value ' : new_state ,
188- 'value_display ' : 'ON' if new_state else 'OFF' ,
186+ 'previous_value ' : current_value ,
187+ 'previous_value_display ' : 'ON' if current_value else 'OFF' ,
188+ 'new_value ' : new_value ,
189+ 'new_value_display ' : 'ON' if new_value else 'OFF' ,
189190 'unit' : unit
190191 })
191192 else :
192- return jsonify ({'error' : f'Failed to write coil { address } ' }), 500
193+ return jsonify ({'error' : f'Failed to toggle coil { address } ' }), 500
194+
195+ @app .route ('/api/discrete_inputs/<int:address>' , methods = ['GET' ])
196+ def read_discrete_input (address ):
197+ """Read single discrete input"""
198+ unit = request .args .get ('unit' , default = 1 , type = int )
199+ result = modbus_client .read_discrete_inputs (address , 1 , unit = unit )
200+
201+ if result is None :
202+ return jsonify ({'error' : 'Failed to read discrete input' }), 500
203+
204+ return jsonify ({
205+ 'address' : address ,
206+ 'value' : result [0 ],
207+ 'value_display' : 'ON' if result [0 ] else 'OFF' ,
208+ 'unit' : unit
209+ })
193210
194211 @app .route ('/api/discrete_inputs/<int:address>/<int:count>' , methods = ['GET' ])
195212 def read_discrete_inputs (address , count ):
196- """Read discrete inputs"""
213+ """Read multiple discrete inputs"""
197214 unit = request .args .get ('unit' , default = 1 , type = int )
198- result = modbus_client .read_discrete_inputs (address , count , unit )
215+ result = modbus_client .read_discrete_inputs (address , count , unit = unit )
199216
200217 if result is None :
201218 return jsonify ({'error' : 'Failed to read discrete inputs' }), 500
@@ -208,11 +225,27 @@ def read_discrete_inputs(address, count):
208225 'unit' : unit
209226 })
210227
228+ @app .route ('/api/holding_registers/<int:address>' , methods = ['GET' ])
229+ def read_holding_register (address ):
230+ """Read single holding register"""
231+ unit = request .args .get ('unit' , default = 1 , type = int )
232+ result = modbus_client .read_holding_registers (address , 1 , unit = unit )
233+
234+ if result is None :
235+ return jsonify ({'error' : 'Failed to read holding register' }), 500
236+
237+ return jsonify ({
238+ 'address' : address ,
239+ 'value' : result [0 ],
240+ 'value_hex' : hex (result [0 ]),
241+ 'unit' : unit
242+ })
243+
211244 @app .route ('/api/holding_registers/<int:address>/<int:count>' , methods = ['GET' ])
212245 def read_holding_registers (address , count ):
213- """Read holding registers"""
246+ """Read multiple holding registers"""
214247 unit = request .args .get ('unit' , default = 1 , type = int )
215- result = modbus_client .read_holding_registers (address , count , unit )
248+ result = modbus_client .read_holding_registers (address , count , unit = unit )
216249
217250 if result is None :
218251 return jsonify ({'error' : 'Failed to read holding registers' }), 500
@@ -221,14 +254,13 @@ def read_holding_registers(address, count):
221254 'address' : address ,
222255 'count' : count ,
223256 'values' : result ,
224- 'values_dict' : {str (i ): val for i , val in enumerate (result , address )},
225- 'hex_values' : [f"0x{ val :04X} " for val in result ],
257+ 'values_hex' : [hex (v ) for v in result ],
226258 'unit' : unit
227259 })
228260
229- @app .route ('/api/holding_registers/<int:address>' , methods = ['POST' ])
261+ @app .route ('/api/holding_registers/<int:address>' , methods = ['POST' , 'PUT' ])
230262 def write_holding_register (address ):
231- """Write holding register"""
263+ """Write single holding register"""
232264 data = request .get_json ()
233265 if data is None :
234266 return jsonify ({'error' : 'Invalid JSON data' }), 400
@@ -244,17 +276,33 @@ def write_holding_register(address):
244276 'success' : True ,
245277 'address' : address ,
246278 'value' : value ,
247- 'value_hex' : f"0x { value :04X } " ,
279+ 'value_hex' : hex ( value ) ,
248280 'unit' : unit
249281 })
250282 else :
251283 return jsonify ({'error' : f'Failed to write register { address } ' }), 500
252284
285+ @app .route ('/api/input_registers/<int:address>' , methods = ['GET' ])
286+ def read_input_register (address ):
287+ """Read single input register"""
288+ unit = request .args .get ('unit' , default = 1 , type = int )
289+ result = modbus_client .read_input_registers (address , 1 , unit = unit )
290+
291+ if result is None :
292+ return jsonify ({'error' : 'Failed to read input register' }), 500
293+
294+ return jsonify ({
295+ 'address' : address ,
296+ 'value' : result [0 ],
297+ 'value_hex' : hex (result [0 ]),
298+ 'unit' : unit
299+ })
300+
253301 @app .route ('/api/input_registers/<int:address>/<int:count>' , methods = ['GET' ])
254302 def read_input_registers (address , count ):
255- """Read input registers"""
303+ """Read multiple input registers"""
256304 unit = request .args .get ('unit' , default = 1 , type = int )
257- result = modbus_client .read_input_registers (address , count , unit )
305+ result = modbus_client .read_input_registers (address , count , unit = unit )
258306
259307 if result is None :
260308 return jsonify ({'error' : 'Failed to read input registers' }), 500
@@ -263,91 +311,8 @@ def read_input_registers(address, count):
263311 'address' : address ,
264312 'count' : count ,
265313 'values' : result ,
266- 'values_dict' : {str (i ): val for i , val in enumerate (result , address )},
267- 'hex_values' : [f"0x{ val :04X} " for val in result ],
314+ 'values_hex' : [hex (v ) for v in result ],
268315 'unit' : unit
269316 })
270317
271- @app .route ('/api/scan' , methods = ['GET' ])
272- def scan_devices ():
273- """Scan for Modbus devices"""
274- port = auto_detect_modbus_port ()
275- return jsonify ({
276- 'success' : port is not None ,
277- 'port' : port
278- })
279-
280- @app .route ('/api/docs' , methods = ['GET' ])
281- def get_docs ():
282- """Get API documentation"""
283- return jsonify ({
284- 'endpoints' : [
285- {
286- 'path' : '/api/status' ,
287- 'method' : 'GET' ,
288- 'description' : 'Get Modbus connection status'
289- },
290- {
291- 'path' : '/api/coils/<address>' ,
292- 'method' : 'GET' ,
293- 'description' : 'Read single coil' ,
294- 'params' : ['unit (query, optional)' ]
295- },
296- {
297- 'path' : '/api/coils/<address>/<count>' ,
298- 'method' : 'GET' ,
299- 'description' : 'Read multiple coils' ,
300- 'params' : ['unit (query, optional)' ]
301- },
302- {
303- 'path' : '/api/coils/<address>' ,
304- 'method' : 'POST' ,
305- 'description' : 'Write single coil' ,
306- 'body' : {'value' : 'boolean/int/string' , 'unit' : 'int (optional)' }
307- },
308- {
309- 'path' : '/api/toggle/<address>' ,
310- 'method' : 'POST' ,
311- 'description' : 'Toggle coil state' ,
312- 'body' : {'unit' : 'int (optional)' }
313- },
314- {
315- 'path' : '/api/discrete_inputs/<address>/<count>' ,
316- 'method' : 'GET' ,
317- 'description' : 'Read discrete inputs' ,
318- 'params' : ['unit (query, optional)' ]
319- },
320- {
321- 'path' : '/api/holding_registers/<address>/<count>' ,
322- 'method' : 'GET' ,
323- 'description' : 'Read holding registers' ,
324- 'params' : ['unit (query, optional)' ]
325- },
326- {
327- 'path' : '/api/holding_registers/<address>' ,
328- 'method' : 'POST' ,
329- 'description' : 'Write holding register' ,
330- 'body' : {'value' : 'int' , 'unit' : 'int (optional)' }
331- },
332- {
333- 'path' : '/api/input_registers/<address>/<count>' ,
334- 'method' : 'GET' ,
335- 'description' : 'Read input registers' ,
336- 'params' : ['unit (query, optional)' ]
337- },
338- {
339- 'path' : '/api/scan' ,
340- 'method' : 'GET' ,
341- 'description' : 'Scan for Modbus devices'
342- }
343- ]
344- })
345-
346- def run_server ():
347- """Run the Flask server"""
348- app .run (host = host , port = api_port , debug = debug )
349-
350- # Add run method to app
351- app .run_server = run_server
352-
353318 return app
0 commit comments