Skip to content

Instantly share code, notes, and snippets.

@radek-senfeld
Last active January 27, 2019 16:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save radek-senfeld/5086fbc40cc86c06478be85c533a718a to your computer and use it in GitHub Desktop.
Save radek-senfeld/5086fbc40cc86c06478be85c533a718a to your computer and use it in GitHub Desktop.
MySensors Ethernet Gateway Hub
#!/usr/bin/env python3
import asyncore
import optparse
import collections
# Config
GATEWAY_HOST = "your-gateway-hostname-or-ip"
GATEWAY_PORT = 5003
GATEWAY_INIT = [
bytes("\n", "ascii"),
]
SERVER_BACKLOG = 5
#
class Gateway(asyncore.dispatcher):
def __init__(self, host, port):
asyncore.dispatcher.__init__(self)
self.buffer = collections.deque(GATEWAY_INIT)
self.clients = []
self.create_socket()
self.connect((host, port))
def add_client(self, client):
self.clients.append(client)
def remove_client(self, client):
try:
self.clients.remove(client)
except ValueError:
pass
def broadcast(self, message):
print("G -> C: {}". format(message))
for client in self.clients:
client.enqueue(message)
def enqueue(self, message):
print("G <- C: {}". format(message))
self.buffer.append(message)
def writable(self):
return len(self.buffer) > 0
def handle_connect(self):
pass
def handle_close(self):
self.close()
def handle_read(self):
message = self.recv(1024)
if len(message) > 0:
self.broadcast(message)
def handle_write(self):
if len(self.buffer) > 0:
message = self.buffer.popleft()
sent = self.send(message)
if sent < len(message):
self.buffer.appendleft(message[sent:])
class Client(asyncore.dispatcher):
def __init__(self, sock, hub):
asyncore.dispatcher.__init__(self, sock)
self.buffer = collections.deque()
self.hub = hub
def enqueue(self, message):
self.buffer.append(message)
def writable(self):
return len(self.buffer) > 0
def handle_close(self):
self.hub.gateway.remove_client(self)
self.close()
def handle_read(self):
message = self.recv(1024)
if len(message) > 0:
self.hub.gateway.enqueue(message)
def handle_write(self):
if len(self.buffer) > 0:
message = self.buffer.popleft()
sent = self.send(message)
if sent < len(message):
self.buffer.appendleft(message[sent:])
class Hub(asyncore.dispatcher):
def __init__(self, host, port, gateway):
asyncore.dispatcher.__init__(self)
self.gateway = gateway
self.create_socket()
self.set_reuse_addr()
self.bind((host, port))
self.listen(SERVER_BACKLOG)
def handle_accepted(self, sock, addr):
client = Client(sock, self)
self.gateway.add_client(client)
if __name__ == "__main__":
parser = optparse.OptionParser()
parser.add_option("-l", "--listen", dest="host", default="0.0.0.0", help="Hostname or IP address. Default is 0.0.0.0")
parser.add_option("-p", "--port", dest="port", type="int", default=5003, help="Port. Default is 5003")
options, args = parser.parse_args()
gateway = Gateway(GATEWAY_HOST, GATEWAY_PORT)
hub = Hub(options.host, options.port, gateway)
asyncore.loop()
@radek-senfeld
Copy link
Author

Hello everyone,
recently I've deployed MySensors Ethernet Gateway on an iTead's iBoard W5100 and got bit by the Arduino / MySensors limition - single connection to the gateway.

As I'm experimenting with Node-RED, Domoticz and might be adding HomeAssistant to the mix, I tried really hard to find a working solution to this situation and failed.

Arduino and MySensors could be fixed to support up to 4 connections but in the end I decided to solve the problem by a simple Python script that relays gateway messages to all the clients and messages from a client are relayed to the gateway.

I thought someone else could be in the same situation so here you go..

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment