How to configure in Google Core IoT? - python

I've made a python program in Raspberry Pi 3 Model B that's supposed to connect to Google Cloud IoT Core with MQTT-protocol and get configurations. Sending data to Core has worked so far, but I just can't figure out how configuring works! Here's a code that's just supposed to get a config:
import time
import datetime
import jwt
import ssl
import json
import paho.mqtt.client as mqtt
time_now = datetime.datetime.utcnow()
#make key
token = {'iat' : time_now ,
'exp' : time_now + datetime.timedelta(minutes=60),
'aud' : "[PROJECT]"}
r = open("[PRIVATE KEY]", 'r')
pub_key = r.read()
jwt_key = jwt.encode(token, pub_key, algorithm='RS256')
#connect to iot-core
client = mqtt.Client(client_id='projects/[PROJECT]/locations/[LOCATION]/registries/[REGISTER]/devices/[DEVICE]')
client.username_pw_set(username='unused', password=jwt_key)
client.tls_set(ca_certs='/home/pi/.local/lib/python2.7/site-packages/grpc/_cython/_credentials/roots.pem', tls_version=ssl.PROTOCOL_TLSv1_2)
client.connect("mqtt.googleapis.com", 8883)
#configure and change state
state = 0
print state #naturally shows 0
print client.subscribe([DEVICE]/config, qos=1) #doesn't print custom config either, just (0,1)
print state #still shows 0
configuration in Iot Core device id is:
{ "state": 1 }
Even after running the program, the device's "state"-variable stays at 0 and the Core's Configuration & State History state that the CONFIG is "Not yet acknowledged by the device"
How do I get the device's "state" variable change from 0 to 1 from Core?

You have done the half of the job. 2 remarks.
It's maybe a detail, but you name your private key pub_key. And you don't close the file.
Based on this tutorial, you only subscribe to the MQTT. The return tuple (0,1) means MQTT_ERR_SUCCESS on QOS = 1. Thus your are connected. Great! Now, do the second part: consume the messages in the channel, and make your logic (according with the received message, change the state in your app if it's your use case)

Related

How do you read strings from a data register using pymodbus?

I'm trying to use my raspberry pi as a client for modbus communication between it and a S7-1200 Siemens plc. I got it to read integers from holding register, but not strings. When I try to search for a solution online on how to read strings from the plc holding register nothing useful comes up. I tried a program online that is supposed to be able to do it but I just keep getting an error every time I run it. Can anyone help? I have the code for the program and the error message below.
from pymodbus.client.sync import ModbusTcpClient as ModbusClient
from pymodbus.payload import BinaryPayloadDecoder
from pymodbus.constants import Endian
from pymodbus.compat import iteritems
if __name__ == '__main__':
client = ModbusClient("192.168.0.1", port=502, auto_open=True)
client.connect()
result = client.read_holding_registers(1, 1, unit=1)
print("Result : ",result)
decoder = BinaryPayloadDecoder.fromRegisters(result.registers, byteorder=Endian.Big, wordorder=Endian.Big)
decoded = {
'name': decoder.decode_string(10).decode(),
}
for name, value in iteritems(decoded):
print ("%s\t" % name, value)
client.close()
Error Message
Data Register
PLC MB Server Block Setup
for example you want to read speed of a asynchronous motor and you use a driver. You have a raspberry pi. You use python and Modbus TCP Protocol .
speed of motor is registered 40001.
result = client.read_holding_registers(1, 1, unit=1) you can read just 40001 adress.
result = client.read_input_registers(0x01,1, unit=0x01) you can read just 30001 adress.
Your Decoding is fine.
It's your setup & request that's the issue.
PLC Setup looks wrong.
You are also only requesting 1 register to read.
Your request is not getting any response (including error).
Coke = b'436f6b65' = [17263, 27493]
Pizza = b'50697a7a6100' = [20585, 31354, 24832]
Cookies = b'436f6f6b69657300' = [17263, 28523, 26981, 29440]
Pad out with 0's to keep register lengths the same.
Store in plc Modbus registers that can be read.
Coke = b'436f6b6500000000' = [17263, 27493, 0, 0]
Pizza = b'50697a7a61000000' = [20585, 31354, 24832, 0]
Cookies = b'436f6f6b69657300' = [17263, 28523, 26981, 29440]
Request 4 registers per word and decode.
you can't take strings value from modbus communication

Ryu-controller for Mininet network configuration

I'm studing about a ring topology of network in mininet. There are 3 access point, in a triangle configuration: ap1, ap2 and ap3 that are connected each other. There is a station (sta1) that isn't mobile (always connected to ap3) and there is a mobile station (sta2) that moves randomly betweeen ap1 and ap2.
The scope is to ping sta2 from sta1.
I used a stp ryu-controller to avoid broadcast storm. It doesn't work well beacause for example I can ping sta2 when it is connected to ap1, but when it moves to ap2, I can't ping it anymore. How can I solve this problem? I attach my ryu-code:
<---sta2--->
ap1---------ap2
- -
- -
- ap3 -
sta1
from ryu.base import app_manager
from ryu.controller import ofp_event
from ryu.controller.handler import CONFIG_DISPATCHER, MAIN_DISPATCHER
from ryu.controller.handler import set_ev_cls
from ryu.ofproto import ofproto_v1_3
from ryu.lib import dpid as dpid_lib
from ryu.lib import stplib
from ryu.lib.packet import packet
from ryu.lib.packet import ethernet
from ryu.app import simple_switch_13
class SimpleSwitch13(simple_switch_13.SimpleSwitch13):
OFP_VERSIONS = [ofproto_v1_3.OFP_VERSION]
_CONTEXTS = {'stplib': stplib.Stp}
def __init__(self, *args, **kwargs):
super(SimpleSwitch13, self).__init__(*args, **kwargs)
self.mac_to_port = {}
self.stp = kwargs['stplib']
# Sample of stplib config.
# please refer to stplib.Stp.set_config() for details.
config = {dpid_lib.str_to_dpid('0000000000000001'):
{'bridge': {'priority': 0x8000}},
dpid_lib.str_to_dpid('0000000000000002'):
{'bridge': {'priority': 0x9000}},
dpid_lib.str_to_dpid('0000000000000003'):
{'bridge': {'priority': 0xa000}}}
self.stp.set_config(config)
def delete_flow(self, datapath):
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
for dst in self.mac_to_port[datapath.id].keys():
match = parser.OFPMatch(eth_dst=dst)
mod = parser.OFPFlowMod(
datapath, command=ofproto.OFPFC_DELETE,
out_port=ofproto.OFPP_ANY, out_group=ofproto.OFPG_ANY,
priority=1, match=match)
datapath.send_msg(mod)
#set_ev_cls(stplib.EventPacketIn, MAIN_DISPATCHER)
def _packet_in_handler(self, ev):
msg = ev.msg
datapath = msg.datapath
ofproto = datapath.ofproto
parser = datapath.ofproto_parser
in_port = msg.match['in_port']
pkt = packet.Packet(msg.data)
eth = pkt.get_protocols(ethernet.ethernet)[0]
dst = eth.dst
src = eth.src
dpid = datapath.id
self.mac_to_port.setdefault(dpid, {})
self.logger.info("packet in %s %s %s %s", dpid, src, dst, in_port)
# learn a mac address to avoid FLOOD next time.
self.mac_to_port[dpid][src] = in_port
if dst in self.mac_to_port[dpid]:
out_port = self.mac_to_port[dpid][dst]
else:
out_port = ofproto.OFPP_FLOOD
actions = [parser.OFPActionOutput(out_port)]
# install a flow to avoid packet_in next time
if out_port != ofproto.OFPP_FLOOD:
match = parser.OFPMatch(in_port=in_port, eth_dst=dst)
self.add_flow(datapath, 1, match, actions)
data = None
if msg.buffer_id == ofproto.OFP_NO_BUFFER:
data = msg.data
out = parser.OFPPacketOut(datapath=datapath, buffer_id=msg.buffer_id,
in_port=in_port, actions=actions, data=data)
datapath.send_msg(out)
#set_ev_cls(stplib.EventTopologyChange, MAIN_DISPATCHER)
def _topology_change_handler(self, ev):
dp = ev.dp
dpid_str = dpid_lib.dpid_to_str(dp.id)
msg = 'Receive topology change event. Flush MAC table.'
self.logger.debug("[dpid=%s] %s", dpid_str, msg)
if dp.id in self.mac_to_port:
self.delete_flow(dp)
del self.mac_to_port[dp.id]
#set_ev_cls(stplib.EventPortStateChange, MAIN_DISPATCHER)
def _port_state_change_handler(self, ev):
dpid_str = dpid_lib.dpid_to_str(ev.dp.id)
of_state = {stplib.PORT_STATE_DISABLE: 'DISABLE',
stplib.PORT_STATE_BLOCK: 'BLOCK',
stplib.PORT_STATE_LISTEN: 'LISTEN',
stplib.PORT_STATE_LEARN: 'LEARN',
stplib.PORT_STATE_FORWARD: 'FORWARD'}
self.logger.debug("[dpid=%s][port=%d] state=%s",
dpid_str, ev.port_no, of_state[ev.port_state])
What I believe is causing the issue
I believe that the reason as to why sta2 is able to ping sta1 initially is because the flow tables in the OpenFlow Switch are empty. When sta2 pings sta1, the controller adds the flow into the OVSSwitch, and thus creates a flow entry in the flow table.
Due to this entry in the flow table, the two stations are able to ping each other since the location is known and a route is set. Once the station migrates to ap2, there is no new flow entry created and attached to the flow table. Why? Because the controller believes that the flow entry in the flow table is accurate and as such does not need to query the network for the path again.
A method to verify this claim
This can be verified by using the dpctl functionality provided by the mininet console. I'm using a slightly different network architecture below, but my theory still holds.
sta5 migrates to ap1 from ap3
In this case, sta5 was initially present in ap3, and we could ping sta3, which is present in ap2 in the initial state of mobility when sta5 is still associated with `ap3``.
sta5 pings sta3
Running dpctl dump-flows allows us to see that the flows have been added after the initial ping has been made.
dpctl dump-flows response
Now, once sta5 migrates to ap1, you'll notice that the ping fails and that the flows have not been altered, thus proving my statement above.
sta5 has migrated to ap1 and fails to ping sta3
Possible solutions
Coming to what can be done to alleviate this problem, there are a few methods,
Ad-hoc your way through it and dpctl del-flows the station which is migrating.
Develop a script to dissociate flows once the station leaves the AP range.
Develop a script to dissociate flows of the station in the switch when it enters a new AP range.
I realize that this is a pretty late response, but hope that it helps out the people that end up facing this issue later on.

How to implement simple client-server interactions in pure python?

I want to implement an IoT application. I will give here a toy version of what I want to do.
Say I have two clients : 'client1' and 'client2' on REMOTE COMPUTERS, and a server 'server', that regulates the computations. The hard thing for me is the fact that the computations can't be made at the same place.
We have : clients_list = ['client1', 'client2']
I want to simulate an algorithm that looks like this:
The server starts with an initial value server_value
for round in range(R):
client_values_dict = {}
for client_id in clients_list:
server broadcasts server_value to the client 'client_id' # via http
client_value = action(server_value) # executed on clients computer
client broadcasts its value to the server # via http
at the meantime, server waits for the response
server fills dictionary with keys clients_list, values client values obtained with 'action' :
client_values_dict[client_id]
server_value = aggregate(client_values_dict) # executed on server computer
On the client side (in client.py), I have a function:
import time
def action(server_value):
time.sleep(10*random.random())
return server_value + random.random()-0.5
On the server side (in server.py), I have a function:
def aggregate(client_values_dict):
return sum(client_values_dict.values())/len(client_values_dict.values())
I want to implement that : I want to write a loop at server level that performs this. I think what I need is an API to handle client-server interactions and parallel computing.
I thought of using Flask for this but I'm afraid that the loop at server level will be blocked by the app.run(debug=True) loop, and that my code won't run until I break the app with CTRL+C.
I want the computations to be made in parallel by the two clients.
I am not familiar with web developpement, my problem might seem trivial and help is probably to be found everywhere on internet, but I don't know where to look at. Any help is cheerfully welcomed.
Here is an example ofa script that simulates what I want, but online.
# -*- coding: utf-8 -*-
import time
import random
server_value = 0
R = 10
clients_list = ['client1', 'client2']
def action(server_value):
time.sleep(3*random.random())
return server_value + random.random()-0.5
def aggregate(client_values_dict):
return sum(client_values_dict.values())/len(client_values_dict.values())
for round in range(R):
client_values_dict = {}
for client_id in clients_list:
client_value = action(server_value) # executed on clients computer
client_values_dict[client_id] = client_value
server_value = aggregate(client_values_dict)
print(server_value)
Have you tried network zero? It's an amazing networking library that I use all the time.
Install:
pip install networkzero
PyPI link: https://pypi.org/project/networkzero/
Docs: https://networkzero.readthedocs.io/en/latest/
Code sample (from their doc page):
Machine/process A:
import networkzero as nw0
address = nw0.advertise("hello")
while True:
name = nw0.wait_for_message_from(address)
nw0.send_reply_to(address, "Hello " + name)
Machine/process B:
import networkzero as nw0
hello = nw0.discover("hello")
reply = nw0.send_message_to(hello, "World!")
print(reply)
reply = nw0.send_message_to(hello, "Tim")
print(reply)
This library also supports more than just 2 connections on the local WiFi, read the docs for more info.
NOTE: I've used this answer before. You can see it here: How to set up a server for a local wifi multiplayer game for python

OPC UA server implementation

Referencing the following video: An OPC UA sample server in written in python using its opcua module
I am trying to implement this server on my own, so that I can later make modifications to it. I have PyDev for Eclipse installed as used in the video.
Here is the code used in the video:
from opcua import Server
from random import randint
import datetime
import time
server = Server()
url = "opc.tcp://192.168.0.8:4840"
server.set_endpoint(url)
name = "OPC_SIMULATION_SERVER"
addspace = server.register_namespace(name)
node = server.get_objects_node()
Param = node.add_object(addspace, "Parameters")
Temp = Param.add_variable(addspace, "Temperature", 0)
Press = Param.add_variable(addspace, "Pressure", 0)
Time = Param.add_variable(addspace, "Time", 0)
Temp.set_writable()
Press.set_writable()
Time.set_writable()
server.start()
print("Server started at {}".format(url))
while True:
Temperature = randint(10,50)
Pressure = randint(200, 999)
TIME = datetime.datetime.now()
print(Temperature, Pressure, TIME)
Temp.set_value(Temperature)
Press.set_value(Pressure)
Time.set_value(TIME)
time.sleep(2)
When I try to run this code, I get the following errors, which appear to be related to one another:
Error Image
If you could help me identify the source of errors, and possible resolutions to them I would appreciate it.
Edit: I was able to configure the server and it ran as expected. However, I now wish to connect it to a client to read in the data. When I try to do this, the connection is established but no data is read in. What are some potential fixes to this issue?

Slow webservice problem

I create a Python webservice on Linux machine (ubuntu):
import soaplib
import os
from soaplib.core.service import rpc, DefinitionBase, soap
from soaplib.core.model.primitive import String, Integer
from soaplib.core.server import wsgi
from soaplib.core.model.clazz import Array
def runcmd(cmd):
fout = os.popen(cmd)
out = fout.read()
return out
class LinuxServices(DefinitionBase):
#soap(String, String,_returns=Array(String))
def df(self,server, user):
L = []
cmd = 'df -hP | grep "/"'
output = runcmd(cmd).split('\n')
for n in xrange(len(output)-1):
out = output[n].split()
L.append('%s;%s' % (out[5], out[4]))
return L
if __name__=='__main__':
try:
from wsgiref.simple_server import make_server
soap_application = soaplib.core.Application([LinuxServices], 'tns')
wsgi_application = wsgi.Application(soap_application)
server = make_server('0.0.0.0', 7789, wsgi_application)
server.serve_forever()
except ImportError:
print "Error: example server code requires Python >= 2.5"
I created it based on this example: soaplib helloworld
Then (on Windows 7) I created a Silverlight project, where I use this ws to get disk status on my linux server:
Service in Silverlight project:
public class LinuxService
{
[OperationContract]
public List<dfItem> df()
{
List<dfItem> dfItems = new List<dfItem>();
WebReference.Application app = new WebReference.Application();
var result = app.df(new WebReference.df()/*...*/);
foreach (var item in result.dfResult)
{
string[] info = item.Split(';');
dfItem dfItem = new dfItem()
{
MountPoint = info[0].ToString(),
Usage = info[1].ToString()
};
dfItems.Add(dfItem);
}
return dfItems;
}
//...
}
Calling service on page:
protected override void OnNavigatedTo(NavigationEventArgs e)
{
LinuxServiceClient client = new LinuxServiceClient();
client.dfCompleted += new EventHandler<dfCompletedEventArgs>(client_dfCompleted);
client.dfAsync();
}
void client_dfCompleted(object sender, dfCompletedEventArgs e)
{
DG.ItemsSource = e.Result;
DG.Visibility = System.Windows.Visibility.Visible;
}
My problem is that when I navigate to this page, it takes 4-8 seconds to get data from ws (ws in LAN).
I really doubt that line bandwidth can create this wait time...
My question:
Do you have any suggestions what can I do to speed up this?
System Info:
UbuntuServer 11.04
Python: Python 2.7
Soaplib: soaplib 2.0.0-beta2
Windows: Windows 7 sp1
Silverlight: Silverlight 4
I'd recommend using wireshark http://www.wireshark.org/ to 'listen' in on the conversation that is occurring over the network by recording ('capturing') copies of the network traffic that the device can see.
When you start a capture, the amount of data can seem overwhelming, but if you can spot any fragments that look like your SOAP message (should be easy to spot), then you can swiftly filter to just that conversation by right-clicking and selecting 'Follow TCP Stream'.
You can then see the entire conversation between the SOAP service you've written and the silverlight client in a pop-up window.
If that all looks fine, then close the popup window. As an added bonus, wireshark will have filtered out the list of fragments to just those in the conversation with timestamps as to when they happened. Use this to find out whether it's client or server that is being slow to respond.
If there appears to be no real delay, then I would suggest that there is a considerable lag between asking Silverlight to do a SOAP call and it actually making the network call.
Just a cursory benchmark using the suds client and the soaplib hello world example:
>>> def bench_soap(num):
...: start = time.time()
...: for i in range(num):
...: hello_client.service.say_hello("Dave", 5)
...: elapsed = time.time() - start
...: print "Completed %s: ops in %.2f seconds : %.1f ops/sec" % (num, elapsed, num / elapsed)
...:
...:
>>> bench_soap(100)
Completed 100: ops in 0.40 seconds : 247.5 ops/sec
>>> bench_soap(1000)
Completed 1000: ops in 3.81 seconds : 262.5 ops/sec
I've not seen any "lag" or anything like that on my end. Soaplib, seems fast and responsive, so perhaps a Silverlight issue? Or some sort of incompatibility between the two?

Categories

Resources