I have a problem accessing client.close() in readholdingregisters() from closeconnection() in the code below:
class EnergyMeter:
def __init__(self, model, gatewayipaddress, port ,deviceid):
self.model = model
self.gatewayipaddress = gatewayipaddress
self.port = port
self.deviceid = deviceid
def readholdingregisters(self, startingregister, numberofregisters):
from pymodbus3.client.sync import ModbusTcpClient as ModbusClient
client = ModbusClient(self.gatewayipaddress, port=self.port)
client.connect()
if #some code here:
#some other code here
return concatResult
else:
return otherResult
Here I want to close the connection client.connect() from readholdingregisters():
def closeconnection(self):
EnergyMeter.readholdingregisters().client.close()??????????????????
Can you plase give me a good solution how to do it?
Usual approach is , make client as datamember of class.
self.client = ModbusClient(self.gatewayipaddress, port=self.port)
self.client.connect()
#some code here
def closeconnection(self):
self.readholdingregisters()
self.client.close()
However if you want to access method through class EnergyMeter.readholdingregisters()
Then it should be declared as staticmethod or classmethod and this method should return client instance. Link
from pymodbus3.client.sync import ModbusTcpClient as ModbusClient
class EnergyMeter:
def __init__(self, model, gatewayipaddress, port ,deviceid):
self.model = model
self.gatewayipaddress = gatewayipaddress
self.port = port
self.deviceid = deviceid
self.client = ModbusClient(self.gatewayipaddress, port=self.port)
self.client.connect()
def readholdingregisters(self, startingregister, numberofregisters):
if #some code here:
#some other code here
return concatResult
else:
return otherResult
Then, to close, you call energy_meter.client.close() for whatever energy_meter you want to close.
Related
My program is using two different communication channels, and in some cases, I need to publish received events from one channel into another. So the basic structure is something like this:
--fileA.py--
class ChannelA:
def __init__(self, data_store):
self.store = data_store
def read(self):
# Listen for messages on this channel and publish them to another channel.
self.store.update()
def publish(self):
# Send a message over this channel
self.store.update()
--fileB.py--
class ChannelB:
def __init__(self, data_store)
self.store = data_store
def read(self):
# Listen for messages on this channel and publish them to another channel.
self.store.update()
def publish(self):
# Send a message over this channel
self.store.update()
--main.py--
from fileStore import DataStore
from fileA import ChannelA
from fileB import ChannelB
def main():
data = DataStore()
channel_A = ChannelA(data)
channel_A.read()
channel_B = ChannelB(data)
channel_B.read()
if __name__ == '__main__':
main()
So what I would like to achieve in the is that I could for example inside ChannelA call a method ChannelB.publish() and vice versa.
I could of course add ChannelA instance to ChannelB constructor parameter, but I can't do the same for ChannelA, since ChannelB had not yet been created:
class ChannelB:
def __init__(self, data_store, channel)
self.store = data_store
self.channel = channel
One simple way of doing this would be to just initialize both communication channels inside a single class and call the methods inside, but this is something I would like to avoid if possible.
Another simple way of solving this could for example be to just define both instances in the main class and later access them via deferred imports:
--main.py--
from fileStore import DataStore
from fileA import ChannelA
from fileB import ChannelB
def publish_A():
channel_A.publish()
def publish_B():
channel_B.publish()
data = DataStore()
channel_A = ChannelA(data)
channel_B = ChannelB(data)
def main():
channel_A.read()
channel_B.read()
if __name__ == '__main__':
main()
--fileA.py--
...
def publish(self):
import main
main.publish_B()
self.store.update()
...
My question here is, what is the best or preferred way to solve such cases in Python?
So what I ended up doing was the following:
--fileA.py--
class ChannelA:
def __init__(self, data_store):
self.store = data_store
self.publish_other = None
def on_publish_other(self, callback):
self.publish_other = callback
def read(self):
# Listen for messages on this channel and publish them to another channel.
self.store.update()
def publish(self):
# Send a message over this channel
if self.publish_other:
self.publish_other()
self.store.update()
--main.py--
from fileStore import DataStore
from fileA import ChannelA
from fileB import ChannelB
def main():
data = DataStore()
channel_A = ChannelA(data)
channel_B = ChannelB(data)
channel_A.on_publish_other(channel_B.publish)
channel_A.read()
channel_B.read()
if __name__ == '__main__':
main()
I am trying to build a coap server, in which I can add a new resource without the need to stop the server, recode it and restart .my server is suppossed to host two types of resources, "sensors(Sens-Me)" and "Actuators(Act-Me)" . I want that if I press the A key, a new instance of actuator should be added to the server, likewise If i Press S for Sensor .Below is my code :
from coapthon.resources.resource import Resource
from coapthon.server.coap import CoAP
class Sensor(Resource):
def __init__(self,name="Sensor",coap_server=None):
super(Sensor,self).__init__(name,coap_server,visible=True,observable=True,allow_children=True)
self.payload = "This is a new sensor"
self.resource_type = "rt1"
self.content_type = "application/json"
self.interface_type = "if1"
self.var = 0
def render_GET(self,request):
self.payload = "new sensor value ::{}".format(str(int(self.var+1)))
self.var +=1
return self
class Actuator(Resource):
def __init__(self,name="Actuator",coap_server=None):
super(Actuator,self).__init__(name,coap_server,visible=True,observable=True)
self.payload="This is an actuator"
self.resource_type="rt1"
def render_GET(self,request):
return self
class CoAPServer(CoAP):
def __init__(self, host, port, multicast=False):
CoAP.__init__(self,(host,port),multicast)
self.add_resource('sens-Me/',Sensor())
self.add_resource('act-Me/',Actuator())
print "CoAP server started on {}:{}".format(str(host),str(port))
print self.root.dump()
def main():
ip = "0.0.0.0"
port = 5683
multicast=False
server = CoAPServer(ip,port,multicast)
try:
server.listen(10)
print "executed after listen"
except KeyboardInterrupt:
server.close()
if __name__=="__main__":
main()
I am not sure what exactly do you want to do.
Is it just to replace a resource on the same route or add a new one?
Replace a resource
It is not possible according to the current coapthon version source:
https://github.com/Tanganelli/CoAPthon/blob/b6983fbf48399bc5687656be55ac5b9cce4f4718/coapthon/server/coap.py#L279
try:
res = self.root[actual_path]
except KeyError:
res = None
if res is None:
if len(paths) != i:
return False
resource.path = actual_path
self.root[actual_path] = resource
Alternatively, you can solve it in scope of request.
Say, have a registry of handlers which are used by resources and can be changed on a user input event. Well, you'll not be able to add new routes.
If you absolutely need that feature, you may request it from a developer or contribute to that project.
Add a new resource
I have extended your snippet a little bit.
I have a little experience in Python so I an not sure I've made everything properly, but it works.
There is a separate thread polling the user input and adding the same resource. Add the needed code there.
from coapthon.resources.resource import Resource
from coapthon.server.coap import CoAP
from threading import Thread
import sys
class Sensor(Resource):
def __init__(self,name="Sensor",coap_server=None):
super(Sensor,self).__init__(name,coap_server,visible=True,observable=True,allow_children=True)
self.payload = "This is a new sensor"
self.resource_type = "rt1"
self.content_type = "application/json"
self.interface_type = "if1"
self.var = 0
def render_GET(self,request):
self.payload = "new sensor value ::{}".format(str(int(self.var+1)))
self.var +=1
return self
class Actuator(Resource):
def __init__(self,name="Actuator",coap_server=None):
super(Actuator,self).__init__(name,coap_server,visible=True,observable=True)
self.payload="This is an actuator"
self.resource_type="rt1"
def render_GET(self,request):
return self
class CoAPServer(CoAP):
def __init__(self, host, port, multicast=False):
CoAP.__init__(self,(host,port),multicast)
self.add_resource('sens-Me/',Sensor())
self.add_resource('act-Me/',Actuator())
print "CoAP server started on {}:{}".format(str(host),str(port))
print self.root.dump()
def pollUserInput(server):
while 1:
user_input = raw_input("Some input please: ")
print user_input
server.add_resource('sens-Me2/', Sensor())
def main():
ip = "0.0.0.0"
port = 5683
multicast=False
server = CoAPServer(ip,port,multicast)
thread = Thread(target = pollUserInput, args=(server,))
thread.setDaemon(True)
thread.start()
try:
server.listen(10)
print "executed after listen"
except KeyboardInterrupt:
print server.root.dump()
server.close()
sys.exit()
if __name__=="__main__":
main()
I'm having a strange phenomena in Python with callback functions and handlers.
I use ZMQ to handle my communication and use a stream for the socket. I have the base class:
import multiprocessing
import zmq
from concurrent.futures import ThreadPoolExecutor
from zmq.eventloop import ioloop, zmqstream
from zmq.utils import jsonapi as json
# Types of messages
TYPE_A = 'type_a'
TYPE_B = 'type_b'
class ZmqProcess(multiprocessing.Process):
def __init__(self):
super(ZmqProcess, self).__init__()
self.context = None
self.loop = None
self.handle_stream = None
def setup(self):
self.context = zmq.Context()
self.loop = ioloop.IOLoop.instance()
def send(self, msg_type, msg, host, port):
sock = zmq.Context().socket(zmq.PAIR)
sock.connect('tcp://%s:%s' % (host, port))
sock.send_json([msg_type, msg])
def stream(self, sock_type, addr):
sock = self.context.socket(sock_type)
if isinstance(addr, str):
addr = addr.split(':')
host, port = addr if len(addr) == 2 else (addr[0], None)
if port:
sock.bind('tcp://%s:%s' % (host, port))
else:
port = sock.bind_to_random_port('tcp://%s' % host)
stream = zmqstream.ZMQStream(sock, self.loop)
return stream, int(port)
class MessageHandler(object):
def __init__(self, json_load=-1):
self._json_load = json_load
self.pool = ThreadPoolExecutor(max_workers=10)
def __call__(self, msg):
i = self._json_load
msg_type, data = json.loads(msg[i])
msg[i] = data
if msg_type.startswith('_'):
raise AttributeError('%s starts with an "_"' % msg_type)
getattr(self, msg_type)(*msg)
And I have a class that inherits from it:
import zmq
import zmq_base
class ZmqServerMeta(zmq_base.ZmqProcess):
def __init__(self, bind_addr, handlers):
super(ZmqServerMeta, self).__init__()
self.bind_addr = bind_addr
self.handlers = handlers
def setup(self):
super(ZmqServerMeta, self).setup()
self.handle_stream, _ = self.stream(zmq.PAIR, self.bind_addr)
self.handle_stream.on_recv(StreamHandler(self.handle_stream, self.stop,
self.handlers))
def run(self):
self.setup()
self.loop.start()
def stop(self):
self.loop.stop()
class StreamHandler(zmq_base.MessageHandler):
def __init__(self, handle_stream, stop, handlers):
super(StreamHandler, self).__init__()
self._handle_stream = handle_stream
self._stop = stop
self._handlers = handlers
def type_a(self, data):
if zmq_base.TYPE_A in self._handlers:
if self._handlers[zmq_base.TYPE_A]:
for handle in self._handlers[zmq_base.TYPE_A]:
self.pool.submit(handle, data)
else:
pass
else:
pass
def type_b(self, data):
if zmq_base.TYPE_B in self._handlers:
if self._handlers[zmq_base.TYPE_B]:
for handle in self._handlers[zmq_base.TYPE_B]:
self.pool.submit(handle, data)
else:
pass
else:
pass
def endit(self):
self._stop()
Additionally, I have a class that I want to use as storage. And here is where the trouble starts:
import threading
import zmq_server_meta as server
import zmq_base as base
class Storage:
def __init__(self):
self.list = []
self.list_lock = threading.RLock()
self.zmq_server = None
self.host = '127.0.0.1'
self.port = 5432
self.bind_addr = (self.host, self.port)
def setup(self):
handlers = {base.TYPE_A: [self. remove]}
self.zmq_server = server.ZmqServerMeta(handlers=handlers, bind_addr=self.bind_addr)
self.zmq_server.start()
def add(self, data):
with self.list_lock:
try:
self.list.append(data)
except:
print "Didn't work"
def remove(self, msg):
with self.list_lock:
try:
self.list.remove(msg)
except:
print "Didn't work"
The idea is that that class stores some global information that it receives.
It is all started in a file to test:
import sys
import time
import storage
import zmq_base as base
import zmq_server_meta as server
def printMsg(msg):
print msg
store = storage.Storage()
store.setup()
handlers = {base.TYPE_B: [printMsg]}
client = server.ZmqServerMeta(handlers=handlers, bind_addr=('127.0.0.1', 5431))
client.start()
message = "Test"
store.add(message)
client.send(base.TYPE_A, message, '127.0.0.1', 5432)
I simplified it to reduce clutter. Instead of just adding it, it is usually send and then a response comes back. The response, the client sending, should be processed by the correct callback, remove(), and it should remove something out of the list. The problem that occurs is, that the remove() function sees an empty list, although there should be an element in the list. If I check from the testing file, I can see the element after it was added, and if I call remove() from there, I see a non-empty list and can remove it. My question is, why does the callback sees an empty list and how can I make sure it does see the correct elements in the list?
Kind regards
Patrick
I believe the problem lays in the fact that the ZmqProcess class inherits from multiprocessing.Process. Multiprocessing does not allow to share objects among different processes, except by using a shared memory map using Value or Array ( as can be seen in the documentation: https://docs.python.org/3/library/multiprocessing.html#sharing-state-between-processes )
If you want to use your custom object, you can use a Server process / proxy object, which can be found in on the same page of the documentation.
So you can, for instance, define a manager in the init function of the Storage class like: self.manager = Manager() Afterwards you put self.list = self.manager.list(). This should do the trick.
I need to pass a kwarg to the parent class of my equivalent of FingerFactoryFromService using super.
I know I am actually passing the kwarg to IFingerFactory because that is also where I pass the service that ends up in init FingerFactoryFromService and I can understand that it is getting tripped up somewhere in the component system but I cannot think of any other way.
The error I keep getting is
exceptions.TypeError: 'test' is an invalid keyword argument for this function
Versions of code in my virtualenv are:
pip (1.4.1)
setuptools (1.1.6)
Twisted (13.1.0)
wsgiref (0.1.2)
zope.interface (4.0.5)
This is a cutdown example from the finger tutorial demonstrating the issue:
from twisted.protocols import basic
from twisted.application import internet, service
from twisted.internet import protocol, reactor, defer
from twisted.python import components
from zope.interface import Interface, implements # #UnresolvedImport
class IFingerService(Interface):
def getUser(user): # #NoSelf
"""
Return a deferred returning a string.
"""
def getUsers(): # #NoSelf
"""
Return a deferred returning a list of strings.
"""
class IFingerFactory(Interface):
def getUser(user): # #NoSelf
"""
Return a deferred returning a string.
"""
def buildProtocol(addr): # #NoSelf
"""
Return a protocol returning a string.
"""
def catchError(err):
return "Internal error in server"
class FingerProtocol(basic.LineReceiver):
def lineReceived(self, user):
d = self.factory.getUser(user)
d.addErrback(catchError)
def writeValue(value):
self.transport.write(value + '\r\n')
self.transport.loseConnection()
d.addCallback(writeValue)
class FingerService(service.Service):
implements(IFingerService)
def __init__(self, filename):
self.filename = filename
self.users = {}
def _read(self):
self.users.clear()
for line in file(self.filename):
user, status = line.split(':', 1)
user = user.strip()
status = status.strip()
self.users[user] = status
self.call = reactor.callLater(30, self._read) # #UndefinedVariable
def getUser(self, user):
print user
return defer.succeed(self.users.get(user, "No such user"))
def getUsers(self):
return defer.succeed(self.users.keys())
def startService(self):
self._read()
service.Service.startService(self)
def stopService(self):
service.Service.stopService(self)
self.call.cancel()
class FingerFactoryFromService(protocol.ServerFactory):
implements(IFingerFactory)
protocol = FingerProtocol
#def __init__(self, srv):
def __init__(self, srv, test=None):
self.service = srv
## I need to call super here because my equivalent of ServerFactory requires
## a kwarg but this cutdown example doesnt so I just assign it to a property
# super(FingerFactoryFromService, self).__init__(test=test)
self.test_thing = test or 'Default Something'
def getUser(self, user):
return self.service.getUser(user)
components.registerAdapter(FingerFactoryFromService,
IFingerService,
IFingerFactory)
application = service.Application('finger')
serviceCollection = service.IServiceCollection(application)
finger_service = FingerService('/etc/passwd')
finger_service.setServiceParent(serviceCollection)
#line_finger_factory = IFingerFactory(finger_service)
line_finger_factory = IFingerFactory(finger_service, test='Something')
line_finger_server = internet.TCPServer(1079, line_finger_factory)
line_finger_server.setServiceParent(serviceCollection)
This has nothing to do with the component system. What you want to do is override the Factory's buildProtocol method, as documented here:
https://twistedmatrix.com/documents/current/core/howto/servers.html#auto9
Trying to convert a server written in C++ into Python. The server was written to be Asynchronous/Non Blocking. What works in C++ doesn't seem to want to work for me in Python
I am using PyQT4. I read Python you have to create the event loop or something along those lines any ideas are greatly appreciated
I should mention what seems to not work is that the incomingConnection function in Class Server is never called.
*cheers
import sys
from PyQt4.QtCore import *
from PyQt4.QtNetwork import *
class Client(QObject):
def __init__(self, parent=None):
QObject.__init__(self)
QThreadPool.globalInstance().setMaxThreadCount(15)
def SetSocket(self, Descriptor):
self.socket = QTcpSocket(self)
self.connect(self.socket, SIGNAL("connected()"), SLOT(self.connected()))
self.connect(self.socket, SIGNAL("disconnected()"), SLOT(self.disconnected()))
self.connect(self.socket, SIGNAL("readyRead()"), SLOT(self.readyRead()))
self.socket.setSocketDescriptor(Descriptor)
print "Client Connected from IP %s" % self.socket.peerAddress().toString()
def connected(self):
print "Client Connected Event"
def disconnected(self):
print "Client Disconnected"
def readyRead(self):
msg = self.socket.readAll()
print msg
class Server(QObject):
def __init__(self, parent=None):
QObject.__init__(self)
def incomingConnection(self, handle):
print "incoming"
self.client = Client(self)
self.client.SetSocket(handle)
def StartServer(self):
self.server = QTcpServer()
if self.server.listen(QHostAddress("0.0.0.0"), 8888):
print "Server is awake"
else:
print "Server couldn't wake up"
def main():
app = QCoreApplication(sys.argv)
Server().StartServer()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
incomingConnection is not called because QTcpServer's base implementation of the function is called. as incomingConnection is a vitual function, you just have to assign your's to QTcpServer's incomingConnection attribute, like this:
class Server(QObject):
def __init__(self, parent=None):
QObject.__init__(self)
def incomingConnection(self, handle):
print "incoming"
self.client = Client(self)
self.client.SetSocket(handle)
def StartServer(self):
self.server = QTcpServer()
self.server.incomingConnection = self.incomingConnection
if self.server.listen(QHostAddress("0.0.0.0"), 8888):
print "Server is awake"
else:
print "Server couldn't wake up"
you can check out PySide's documentation, as it's much more pythonic than PyQt's, currently hosted only here:
http://srinikom.github.com/pyside-docs/