Simple UDP Sensor Server in Python <=> Object Pascal
2023.09.27 17:37
# This is needed for accessing sensor data which library supports only python or c++
import socket # For UDP Communication to PC
import struct # For ??
import sys # For sys.stderr (Print to screen)
myip = '127.0.0.1' # Development Mode (Local IP)
machinename = 'SENSE-NET'
message = ''
old_ar_rcv = ''
shortstr = ''
multicast_group = (myip, 6767) # Actual Run Mode in PI (PC(Overmind)'s IP)
sockettimeout = 2.2
# Create the datagram socket
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
# Set a timeout so the socket does not block indefinitely when trying
# to receive data.
sock.settimeout(sockettimeout) # original (0.2)
# Set the time-to-live for messages to 1 so they do not go past the
# local network segment.
ttl = struct.pack('b', 1)
sock.setsockopt(socket.IPPROTO_IP, socket.IP_MULTICAST_TTL, ttl)
try:
# Send data to multicast group
# bytesToSend = str.encode(msgFromServer)
sent = sock.sendto(str.encode(machinename), multicast_group)
while True: #keep going
try:
# Get message from Arduino
# ar_rcv = ar_port.readline() # read 30 characters
# ar_rcv = ar_rcv.strip('\n')
# if len(ar_rcv) < 2:
# ar_rcv = old_ar_rcv
# else:
# if old_ar_rcv != ar_rcv :
# print >> sys.stderr, ar_rcv
# old_ar_rcv = ar_rcv
# sent == sock.sendto(ar_rcv, multicast_group)
# to write to arduino, use: ar_port.write('My Message')
data, server = sock.recvfrom(10)
# print >> sys.stderr, 'received "%s" from %s' % (data, server)
if data != '.':
if message != data :
message = ''
# ar_port.write(data)
print >> sys.stderr, 'to ar. "%s" ' % (data)
# print('to ar. "%s" ' % (data))
sent == sock.sendto(str.encode(data), multicast_group)
message = data
except socket.timeout:
print >> sys.stderr, 'UDP Timeout' % (data, server)
#print('UDP Timeout')
break
else:
if data != '.': # If data from Overmind is not '.'
#i = 1 # dummy, do nothing
print >> sys.stderr, 'received "%s" from %s' % (data, server)
finally:
print >>sys.stderr, 'closing socket'
#print('Error : closing socket')
sock.close()
exit()
// Comminicating to above UDP server from Object Pascal
unit UDPTest;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, StdCtrls,
UTF8Process, lNetComponents, lNet;
type
{ TfrmUDPTest }
TfrmUDPTest = class(TForm)
cbKeepAlive: TCheckBox;
eExecCommand: TEdit;
eUDPCommand: TEdit;
eHost: TEdit;
ePort: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
lblHeart: TLabel;
lblStatus1: TLabel;
LUDP: TLUDPComponent;
m: TMemo;
mTokenBOT: TMemo;
mRecv: TMemo;
ProcessUTF8_1: TProcessUTF8;
tAlive: TTimer;
TimerQuit: TTimer;
tSecond: TTimer;
procedure eExecCommandKeyPress(Sender: TObject; var Key: char);
procedure eUDPCommandKeyPress(Sender: TObject; var Key: char);
procedure FormClose(Sender: TObject; var CloseAction: TCloseAction);
procedure FormCreate(Sender: TObject);
procedure LUDPError(const msg: string; aSocket: TLSocket);
procedure LUDPReceive(aSocket: TLSocket);
procedure mRecvChange(Sender: TObject);
procedure tAliveTimer(Sender: TObject);
procedure TimerQuitTimer(Sender: TObject);
procedure tSecondTimer(Sender: TObject);
private
public
FValueQueue : array[1..132] of Byte;
FQueueHead, FQueueMax : integer;
FNet: TLConnection;
FIsServer, FirstInited: Boolean;
secno, HeartbeatNo : integer;
s, ts: string;
procedure SendToAll(const aMsg: string);
procedure SendMsg(const aMsg: string);
end;
var
frmUDPTest: TfrmUDPTest;
implementation
{$R *.lfm}
{ TfrmUDPTest }
procedure TfrmUDPTest.SendToAll(const aMsg: string);
var
n: Integer;
begin
if FNet is TLUdp then begin // UDP, use broadcast
n := TLUdp(FNet).SendMessage(aMsg, LADDR_BR);
if n < Length(aMsg) then
m.Append('Error on send [' + IntToStr(n) + ']');
end;
end;
procedure TfrmUDPTest.SendMsg(const aMsg: string);
begin
LUDP.Host := eHost.text;
if Length(aMsg) > 0 then begin
FIsServer := false;
FNet.SendMessage(aMsg);
FIsServer := True;
end;
end;
procedure TfrmUDPTest.tSecondTimer(Sender: TObject);
begin
inc(secno);
if (secno mod 10) = 9 then lblHeart.visible := true;
if (secno mod 10) = 0 then lblHeart.visible := false;
end;
procedure TfrmUDPTest.eExecCommandKeyPress(Sender: TObject; var Key: char);
begin
if Key = #13 then begin
ProcessUTF8_1.CommandLine:= eExecCommand.Text;
ProcessUTF8_1.Execute;
m.Lines.LoadFromStream(ProcessUTF8_1.Output);
end;
end;
procedure TfrmUDPTest.eUDPCommandKeyPress(Sender: TObject; var Key: char);
var
str: String;
rst : integer;
begin
if Key = #13 then begin
str := eUDPCommand.Text;
// if NewLine_CB.Checked then
// str := str; // + #13#10;
// rst := SerialESP.WriteData(str);
SendMsg(str);
m.lines.add('Sents : ' + str);
end;
end;
procedure TfrmUDPTest.FormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
if FNet.Connected then
begin
CloseAction := caNone; // make sure we quit gracefuly
FNet.Disconnect; // call disconnect (soft)
TimerQuit.Enabled := True; // if time runs out, quit ungracefully
end; // TimerQuit gives 200 ms deley before close;
end;
procedure TfrmUDPTest.FormCreate(Sender: TObject);
begin
FNet := LUDP;
FIsServer := False;
FirstInited := False; // First received message to activate
// eHost.text := '192.168.1.133';
LUDP.Host := '127.0.0.1';
FNet.Connect('127.0.0.1', 6767);
FIsServer := False;
// To run it as server mode, unblock following code.
// if FNet.Listen(StrToInt(ePort.text)) then begin
// lblStatus1.caption := 'Accepting signal';
// FIsServer := True;
// end;
end;
procedure TfrmUDPTest.LUDPError(const msg: string; aSocket: TLSocket);
begin
m.Append(msg);
end;
procedure TfrmUDPTest.LUDPReceive(aSocket: TLSocket);
var
s1: string;
begin
if aSocket.GetMessage(s1) > 0 then begin
if s1 <> '.' then begin
if s1[1] = '|' then // Message from Arduino
begin
if mTokenBOT.lines.count > 7 then
mTokenBOT.lines.clear;
mTokenBOT.Append(s1);
end
else
begin // Message from PI2
if mRecv.lines.count > 7 then
mRecv.lines.clear;
mRecv.Append(s1);
end;
end;
// activate if first message is received to avoid crash
if not FirstInited then begin
HeartbeatNo := 0;
if not cbKeepAlive.checked then cbKeepAlive.checked := true;
FirstInited := true;
tSecond.enabled := true;
end;
end;
end;
procedure TfrmUDPTest.mRecvChange(Sender: TObject);
begin
end;
procedure TfrmUDPTest.tAliveTimer(Sender: TObject);
begin
if not FirstInited then exit;
if not cbKeepAlive.checked then exit;
inc(HeartbeatNo);
LUDP.Host := eHost.text;
FIsServer := false;
FNet.SendMessage('.');
// lblStatus1.caption := 'HEART : ' + inttostr(HeartbeatNo)
// + ' @ ' + formatdatetime('HH:NN', now);
FIsServer := True;
end;
// .2 second delay close
procedure TfrmUDPTest.TimerQuitTimer(Sender: TObject);
begin
close;
end;
end.