Question about pymodbusTCP server implementaion - tcp

We have a simulator(client) and controller(server).
The controller sends a command signal through ModbusTCP to the simulator.
I want to emulate this controller on my computer.
What I have done
For the test, I wrote pymodbus Server script on my pc and pymodbus Client script on another PC. There was no problem to read holding and input register from client pc.
I connected my clinet pc to controller(server) to know what kind of values I have to send to actual client(simulator). I found out that 8 registers(from 0 to 7) are used to store integer values.
I tried to establish a connection between my pc(sever) and simulator computer(client).I was able to establish a connection and send a response to the client.
Problem
I have no information about this client(simulator) because we have no access to the client script.
I found out that this client sends a request not only for the reading but also for writing.
When I use the holding register, I got an error "illegal data address." But the input register does not show any error. For this reason, I am using input_register to save a specific integer number.
I stored some values on input_register, but sever input_registers are written by client(simulator) as below.
write request from client(simulator)
polling server(pc) with modpoll software
Question
why write requests from the client(simulator) overwrite my input_register? As far as I know, input_register is used for only reading. I assume that I made a mistake in storing a variable on the input_register.
When I make a connection between controller and simulator, wireshark and modpoll show that client(simulator) reads registers (from 0 to 7). But when I make a connection between my server(pc) and client(simulator), my sever response with different register numbers as below. Resister number starts from 1000. Why does simulator request different register start number? ex) from 0: controller, from 1000: PC(sever)
First response from server(pc)
Update! my server can respond with the values but with wrong register numbers. I changed starting register number(0 -->1000).
I attached picture.
response from server(pc)
Please advice me on this issue.
I will do my best effort to solve this issue.
'''
from pymodbus.server.sync import StartTcpServer
from pymodbus.datastore import ModbusSequentialDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.device import ModbusDeviceIdentification
from pymodbus.datastore import ModbusSequentialDataBlock, ModbusSparseDataBlock
from pymodbus.datastore import ModbusSlaveContext, ModbusServerContext
from pymodbus.transaction import ModbusRtuFramer, ModbusBinaryFramer
#%%
import logging
FORMAT = ('%(asctime)-15s %(threadName)-15s'
' %(levelname)-8s %(module)-15s:%(lineno)-8s %(message)s')
logging.basicConfig(format=FORMAT)
log = logging.getLogger()
log.setLevel(logging.DEBUG)
#%%
#%%
def run_server():
store = ModbusSlaveContext(
ir=ModbusSequentialDataBlock(0, [28692,28692,28692,28692,28692,65508,65508,65508
]),zero_mode=True)
context = ModbusServerContext(slaves=store, single=True)
StartTcpServer(context, address=("192.168.1.231", 502))
identity = ModbusDeviceIdentification()
identity.VendorName = 'Pymodbus'
identity.ProductCode = 'PM'
identity.VendorUrl = 'http://github.com/riptideio/pymodbus/'
identity.ProductName = 'Pymodbus Server'
identity.ModelName = 'Pymodbus Server'
identity.MajorMinorRevision = '1.0'
#%%
if __name__ == "__main__":
run_server()
'''
Dear MarcosG,
I attached screen-shots from wireshark as below.
write request from clinet(simulator)
- as you can see clinet(simulator) send a request for writing and register number start from 256.
read response from server(controller)
- Sever(controller) responds to the request of clinet for reading. And it send a respond and register number start from 256.
polling sever with modpoll software
- we can look the values on the registers of sever, as you can see, values are stored in the register from 0 to 7. These values are from controller lever. If I adjust lever, these values are changing.
requested address_exel_File
- We have one more simulator(bridge2). It shows the same register number with both controller(server) and pc(server).
problem: the actual registers of sever which store values are from 0 to 7. However, Client and server communicate with different registers (from 256) which contain "0" values. But there is no issue for adjusting parameters of ship on the simulator.
Best regards
Byeon Seongsu

Related

Adafruit_requests library functions differently than Python requests library

So I'm trying to run a post request to a TD Ameritrade API on an adafruit Magtag device using the adafruit_requests module. I have run the same code in Python using the requests module, which has proven to work fine.
My Magtag device has successfully connected to the internet and executed the test requests adafruit supplied, but will not work with my code and returns a "duplicate headers" error. Below is the complete code that I ran on my MagTag device as well as the error message that was returned.
import ssl
import wifi
import socketpool
import adafruit_requests
import json
# Get wifi details from a secrets.py file
from secrets import secrets
# Connect to wifi
wifi.radio.connect(secrets["ssid"],secrets["password"])
pool = socketpool.SocketPool(wifi.radio)
requests = adafruit_requests.Session(pool, ssl.create_default_context())
# Get json data
refreshToken = ''
client_id = ''
with open("TDtokens.json","r") as tokens_file, open("TDsecrets.json","r") as secrets_file:
refreshToken = json.load(tokens_file)['refresh_token']
client_id = json.load(secrets_file)['client_id']
# Refresh token needs to be triggered every 30 minutes, as authToken expires.
url = r"https://api.tdameritrade.com/v1/oauth2/token"
headers = {'Content-Type':'application/x-www-form-urlencoded'}
data = {'grant_type': 'refresh_token','refresh_token': refreshToken,'client_id':client_id}
authReply = requests.post(url=url, headers=headers, data=data)
print(authReply.json())
{'fault': {'faultstring': 'Duplicate Header "Content-Type"', 'detail': {'errorcode': 'protocol.http.DuplicateHeader'}}}
I have done a lot of tweaking and I can't figure out where this error is coming from, whether from adafruit or TD Ameritrade's side. Upon reading the documentation for the adafruit_requests module I do not see any reason why an error would be raised for this type of request.
If you have any experience with adafruit or Python requests any advice would be greatly appreciated.

httr authentication login/password in "xtb" API

I need to authenticate and get prices using this api
I have no experience with api so my attempt to login gives an error
login <- "vikov98261#jesdoit.com"
pass <- "QazQaz123"
library(httr)
resp <- POST("xapi.xtb.com",
body=list(userId = login,
password = pass) )
Error in curl::curl_fetch_memory(url, handle = handle) :
Failed to connect to xapi.xtb.com port 80: Timed out
Can someone show me how to do it right.
I would like an example of how the login request works.
And also I would like an example of how to get the prices of any currency
Their API documentation uses WebSocket syntax, so I assume xapi.xtb.com may only be used by the clients. I, for once, only managed to get WebSocket to work.
In order to make this work in r you would need a WebSocket client library for r, such as websocket. Once you have that:
1. Define connection
ws <- WebSocket$new("wss://ws.xtb.com/demo")
2. Log in
WebSocket clients work with events. The 'open' event is generated once the connection is established and the 'message' events are generated when messages are received. You need to write handlers for them to orchestrate the way you want to use the XTB API.
The first event will be 'open', so use that to send the login command.
ws$onOpen(function(event) {
ws$send({
"command":"login",
"arguments": {
"userId":"1000",
"password":"PASSWORD",
"appId":"test",
"appName":"test"
}
})
})
3. Your logic
The response to your login command will trigger a 'message' event, the output of which you will need to handle in your code.
ws$onMessage( <your-code-goes-here> )
The easiest way would probably be to send new commands based on what is the structure of the received message, although it can get really complicated with many commands.
4. Connect
After all handles have been defined, don't forget to connect.
ws$connect()

Is there a mistake in the token validation documentation? Or am I getting this wrong?

In this section of the sign-in guide,
https://developers.google.com/identity/sign-in/android/backend-auth#using-a-google-api-client-library,
There is this code snippet
# Specify the CLIENT_ID of the app that accesses the backend:
id_token.verify_oauth2_token(token, requests.Request(),CLIENT_ID)
This correctly validates the token when I pass my server's client ID, but fails when I pass the android app's client it.
However, the comment suggests that it should be the android app's client ID that should get passed here! And that also makes more sense from a security perspective.
Further down, I can find the following Python code sample
# Or, if multiple clients access the backend server:
# idinfo = id_token.verify_oauth2_token(token, requests.Request())
# if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
# raise ValueError('Could not verify audience.')
I have played around a bit and it seems to me that idinfo["aud"] key carries the client ID of the server, where as idinfo["azp"] carries the client ID of the client.
If I understand it right, in this line we are supposed to verify the client id of the android app client!
So it should read:
if idinfo['azp'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
raise ValueError('Could not verify audience.')
I feel like I must be getting something wrong here, but what is it?

Sockets.receive stops receiving, while there is still data incoming

I have to Transfer a string from an asp.net web application to a VB.NET Desktop application. The data is send completely but the receiving end stops after About 8 kB of Data. There is no error message, it just ignores the rest of the data.
The transferred string is a semicolon separated list of print instructions and data. Normally the string is around 1 to 1.5kb of size. But now we have to Transfer a customers signature as well. This "Blows" the data up to about 15kb on average.
We are working with System.Net.Sockets.Socket.
On my development System, Windows 10, it works fine. On older machines, Windows Server 2008-R2, our Clients machines, the data is cut short.
The Software is compiled with .Net 4.7.2 on the Web-App side and 4.5 on the Desktop side.
We traced the Transfer with Wireshark and it appears that the Receiver receives exactly 6 TCP Packages and then ignores the rest. There is no error message and no disconnect.
I've tried to Change the Send/Receive Parameters to include an error flag, but it is Always returned ok. Using Send/Receive without Parameters, produced the same results.
Send Code from the Website:
Try
remoteEP = New IPEndPoint(_ipAddress, _listenPort)
clientSocket.SendTimeout = 2000
clientSocket.Connect(remoteEP)
clientSocket.Send(Encoding.ASCII.GetBytes(dataString), 0,
Encoding.ASCII.GetBytes(dataString).Count,
SocketFlags.None, SendError)
Catch ex As Exception
log.Fatal("IP socket init. failed", ex)
Finally
clientSocket.Close()
End Try
Receive code from the Printer-App
//Wait for incoming Data
clientSocket = server.Accept
//Signal receiving state to the frontend.
setReceiving()
ReDim receivedBytes(100001)
//Wait a second to make sure everything has been transferred
Threading.Thread.Sleep(1000)
Dim SError As SocketError
clientSocket.ReceiveTimeout = 1000
Try
receivedBytesLength = clientSocket.Receive(receivedBytes, 0,
100001, SocketFlags.None, SError)
Catch ex As SocketException
log.Debug("startReceiver - ReceiveTimeout erreicht", ex)
End Try
I need all the data to be transferred or at least an error message, so I can work on the problem.

ORA-29270: too many open HTTP requests

Can someone help me with this problem that occurs whenever you run a TRIGGER, but works in a normal PROCEDURE?
TRIGGER:
create or replace
procedure testeHTTP(search varchar2)
IS
Declare
req sys.utl_http.req;<BR>
resp sys.utl_http.resp;<BR>
url varchar2(500);
Begin
url := 'http://www.google.com.br';
dbms_output.put_line('abrindo');
-- Abrindo a conexão e iniciando uma requisição
req := sys.utl_http.begin_request(search);
dbms_output.put_line('preparando');
-- Preparandose para obter as respostas
resp := sys.utl_http.get_response(req);
dbms_output.put_line('finalizando response');
-- Encerrando a comunicação request/response
sys.utl_http.end_response(resp);
Exception
When Others Then
dbms_output.put_line('excecao');
dbms_output.put_line(sys.utl_http.GET_DETAILED_SQLERRM());
End;
close your user session and then the problem is fixed.
Internal there is a limit from 5 http requests.
Might a problem is the missing: utl_http.end_response
or an exception in the app and not a close from the resp object.
modify the code like that:
EXCEPTION
WHEN UTL_HTTP.TOO_MANY_REQUESTS THEN
UTL_HTTP.END_RESPONSE(resp);
you need to close your requests once you are done with them, it does not happen automatically (unless you disconnect form the db entirely)
It used to be utl_http.end_response, but I am not sure if it is the same api any more.
Usually we need UTL_HTTP.END_RESPONSE(resp); to avoid of ORA-29270: too many open HTTP requests, but I think I reproduced the problem of #Clóvis Santos in Oracle 19c.
If web-service always returns status 200 (success) then too many open HTTP requests never happens. But if persistent connections are enabled and web-service returns status 404, behavior becomes different.
Let`s call something that always return 404.
First call of utl_http.begin_request returns normally and opens new persistent connection. We can check it with select utl_http.get_persistent_conn_count() from dual;. Second call causes an exception inside utl_http.begin_request and persistent connection becomes closed. (Exception is correctly handled with end_response/end_request).
If I continue then each odd execution returns 404 normally and each even execution gives an exception (handled correctly of course).
After some iterations I get ORA-29270: too many open HTTP requests. If web-service returns status 200 everything goes normally.
I guess, it happens because of the specific web-service. Probable it drops persistent connection after 404 and doesn't after 200. Second call tries to reuse request on persistent connection but it doesn't exist and causes request leak.
If I use utl_http.set_persistent_conn_support (false, 0); once in my session the problem disappears. I can call web-service as many times as I need.
Resolution:
Try to switch off persistent connection support. Probable, on the http-server persistent connections work differently for different requests. Looks like a bug.

Resources