Skip to content

Commit ab69923

Browse files
author
Catalin Ioana
committed
lib/lora_mesh: updated Pymesh example, as release v1.20.0.rc7
1 parent fda5e98 commit ab69923

File tree

2 files changed

+77
-105
lines changed

2 files changed

+77
-105
lines changed

lib/lora_mesh/loramesh.py

Lines changed: 52 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
import ubinascii
66
import pycom
77

8-
__version__ = '1'
8+
__version__ = '2'
99

1010
class Loramesh:
1111
""" Class for using Lora Mesh - openThread """
1212

13-
STATE_NOT_CONNECTED = const(0)
14-
STATE_CHILD = const(1)
15-
STATE_ROUTER = const(2)
16-
STATE_LEADER = const(3)
17-
#STATE_CHILD_SINGLE = const(4)
18-
STATE_LEADER_SINGLE = const(4)
13+
STATE_DISABLED = const(0)
14+
STATE_DETACHED = const(1)
15+
STATE_CHILD = const(2)
16+
STATE_ROUTER = const(3)
17+
STATE_LEADER = const(4)
18+
STATE_LEADER_SINGLE = const(5)
1919

20-
# rgb LED color for each state: not connected, child, router, leader and single leader
21-
RGBLED = [0x0A0000, 0x0A0A0A, 0x000A00, 0x00000A, 0x07070A]
20+
# rgb LED color for each state: disabled, detached, child, router, leader and single leader
21+
RGBLED = [0x0A0000, 0x0A0000, 0x0A0A0A, 0x000A00, 0x0A000A, 0x000A0A]
2222

2323
# address to be used for multicasting
2424
MULTICAST_MESH_ALL = 'ff03::1'
@@ -33,25 +33,37 @@ def __init__(self, lora=None):
3333
self.lora = LoRa(mode=LoRa.LORA, region=LoRa.EU868, bandwidth=LoRa.BW_125KHZ, sf=7)
3434
else:
3535
self.lora = lora
36-
self.lora.mesh()
36+
self.mesh = self.lora.Mesh()
3737
self.rloc = ''
3838
self.ip_eid = ''
3939
self.ip_link = ''
4040
self.single = True
41-
self.state_id = STATE_NOT_CONNECTED
41+
self.state = STATE_DISABLED
42+
43+
def _state_update(self):
44+
""" Returns the Thread role """
45+
self.state = self.mesh.state()
46+
if self.state < 0:
47+
self.state = self.STATE_DISABLED
48+
return self.state
49+
50+
def _rloc_ip_net_addr(self):
51+
""" returns the family part of RLOC IPv6, without last word (2B) """
52+
self.net_addr = ':'.join(self.rloc.split(':')[:-1]) + ':'
53+
return self.net_addr
4254

4355
def _update_ips(self):
4456
""" Updates all the unicast IPv6 of the Thread interface """
45-
ip_all = self.lora.cli('ipaddr')
46-
ips = ip_all.split('\r\n')
47-
try:
48-
rloc16 = int(self.lora.cli('rloc16'), 16)
49-
except Exception:
50-
rloc16 = 0xFFFF
57+
ips = self.mesh.ipaddr()
58+
self.rloc16 = self.mesh.rloc()
5159
for line in ips:
5260
if line.startswith('fd'):
5361
# Mesh-Local unicast IPv6
54-
if int(line.split(':')[-1], 16) == rloc16:
62+
try:
63+
addr = int(line.split(':')[-1], 16)
64+
except Exception:
65+
continue
66+
if addr == self.rloc16:
5567
# found RLOC
5668
# RLOC IPv6 has x:x:x:x:0:ff:fe00:RLOC16
5769
self.rloc = line
@@ -63,87 +75,47 @@ def _update_ips(self):
6375
self.ip_link = line
6476

6577
def is_connected(self):
66-
""" Returns true if it is connected if its Child, Router or Leader """
78+
""" Returns true if it is connected as either Child, Router or Leader """
6779
connected = False
68-
state = self.state()
69-
if state == STATE_CHILD or state == STATE_ROUTER or state == STATE_LEADER:
80+
self.state = self.mesh.state()
81+
if self.state in (STATE_CHILD, STATE_ROUTER, STATE_LEADER, STATE_LEADER_SINGLE):
7082
connected = True
7183
return connected
7284

73-
def state(self):
74-
""" Returns the Thread role """
75-
state_code = STATE_NOT_CONNECTED
76-
try:
77-
state = self.lora.cli('state')
78-
79-
if state.startswith('child'):
80-
state_code = STATE_CHILD
81-
elif state.startswith('router'):
82-
state_code = STATE_ROUTER
83-
elif state.startswith('leader'):
84-
state_code = STATE_LEADER
85-
self.single = False
86-
single_str = self.lora.cli('singleton')
87-
if single_str.startswith('true'):
88-
self.single = True
89-
state_code = STATE_LEADER_SINGLE
90-
91-
self.state_id = state_code
92-
except Exception:
93-
pass
94-
return state_code
95-
9685
def led_state(self):
9786
""" Sets the LED according to the Thread role """
98-
pycom.rgbled(self.RGBLED[self.state()])
87+
if self.state == STATE_LEADER and self.mesh.single():
88+
pycom.rgbled(self.RGBLED[self.STATE_LEADER_SINGLE])
89+
else:
90+
pycom.rgbled(self.RGBLED[self.state])
9991

10092
def ip(self):
10193
""" Returns the IPv6 RLOC """
10294
self._update_ips()
10395
return self.rloc
10496

105-
def parent_ip(self):
106-
""" Returns the IP of the parent, if it's child node """
107-
ip = None
108-
state = self.state()
109-
if state == STATE_CHILD or state == STATE_ROUTER:
110-
try:
111-
ip_words = self.ip().split(':')
112-
parent_rloc = int(self.lora.cli('parent').split('\r\n')[1].split(' ')[1], 16)
113-
ip_words[-1] = hex(parent_rloc)[2:]
114-
ip = ':'.join(ip_words)
115-
except Exception:
116-
pass
117-
return ip
97+
def neighbors(self):
98+
""" Returns a list with all properties of the neighbors """
99+
return self.mesh.neighbors()
118100

119101
def neighbors_ip(self):
120-
""" Returns a list with IP of the neighbors (children, parent, other routers) """
121-
state = self.state()
122-
neigh = []
123-
if state == STATE_ROUTER or state == STATE_LEADER:
124-
ip_words = self.ip().split(':')
125-
# obtain RLOC16 neighbors
126-
neighbors = self.lora.cli('neighbor list').split(' ')
127-
for rloc in neighbors:
128-
if len(rloc) == 0:
129-
continue
130-
try:
131-
ip_words[-1] = str(rloc[2:])
132-
nei_ip = ':'.join(ip_words)
133-
neigh.append(nei_ip)
134-
except Exception:
135-
pass
136-
elif state == STATE_CHILD:
137-
neigh.append(self.parent_ip())
138-
return neigh
102+
""" Returns a list with IPv6 (as strings) of the neighbors """
103+
neighbors = self.neighbors()
104+
nei_list = []
105+
net_ip = self._rloc_ip_net_addr()
106+
if neighbors is not None:
107+
for nei_rec in neighbors:
108+
nei_ip = net_ip + hex(nei_rec.rloc16)[2:]
109+
nei_list.append(nei_ip)
110+
return nei_list
139111

140112
def ipaddr(self):
141113
""" Returns a list with all unicast IPv6 """
142-
return self.lora.cli('ipaddr').split('\r\n')
114+
return self.mesh.ipaddr()
143115

144116
def cli(self, command):
145117
""" Simple wrapper for OpenThread CLI """
146-
return self.lora.cli(command)
118+
return self.mesh.cli(command)
147119

148120
def ping(self, ip):
149121
""" Returns ping return time, to an IP """
@@ -161,7 +133,7 @@ def ping(self, ip):
161133
def blink(self, num = 3, period = .5, color = None):
162134
""" LED blink """
163135
if color is None:
164-
color = self.RGBLED[self.state()]
136+
color = self.RGBLED[self.state]
165137
for i in range(0, num):
166138
pycom.rgbled(0)
167139
time.sleep(period)

lib/lora_mesh/main.py

Lines changed: 25 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -17,44 +17,29 @@
1717

1818
mesh = Loramesh(lora)
1919

20-
# waiting until it connected to Mesh network and
21-
# it has some valid neighbors
20+
# waiting until it connected to Mesh network
2221
while True:
2322
mesh.led_state()
2423
print("%d: State %s, single %s"%(time.time(), mesh.cli('state'), mesh.cli('singleton')))
2524
time.sleep(2)
2625
if not mesh.is_connected():
2726
continue
2827

29-
neigbors = mesh.neighbors_ip()
30-
if len(neigbors) == 0:
31-
print('No neighbor')
32-
continue
33-
34-
print('Neighbors found: %s'%neigbors)
28+
print('Neighbors found: %s'%mesh.neighbors())
3529
break
3630

3731
# create UDP socket
3832
s = socket.socket(socket.AF_LORA, socket.SOCK_RAW)
3933
myport = 1234
4034
s.bind(myport)
41-
pack_num = 1
42-
msg = "Hello World! MAC: " + MAC + ", pack: "
43-
ip = mesh.ip()
44-
45-
while True:
46-
mesh.led_state()
47-
print("%d: State %s, single %s, IP %s"%(time.time(), mesh.cli('state'), mesh.cli('singleton'), mesh.ip()))
48-
49-
# check if topology changes, maybe RLOC IPv6 changed
50-
new_ip = mesh.ip()
51-
if ip != new_ip:
52-
print("IP changed from: %s to %s"%(ip, new_ip))
53-
ip = new_ip
5435

36+
# handler responisble for receiving packets on UDP Pymesh socket
37+
def receive_pack():
5538
# listen for incomming packets
56-
rcv_data, rcv_addr = s.recvfrom(128)
57-
if len(rcv_data)>0:
39+
while True:
40+
rcv_data, rcv_addr = s.recvfrom(128)
41+
if len(rcv_data) == 0:
42+
break
5843
rcv_ip = rcv_addr[0]
5944
rcv_port = rcv_addr[1]
6045
print('Incomming %d bytes from %s (port %d)'%(len(rcv_data), rcv_ip, rcv_port))
@@ -66,11 +51,26 @@
6651
except Exception:
6752
pass
6853
mesh.blink(7, .3)
69-
continue
54+
55+
pack_num = 1
56+
msg = "Hello World! MAC: " + MAC + ", pack: "
57+
ip = mesh.ip()
58+
mesh.mesh.rx_cb(receive_pack)
59+
60+
# infinite main loop
61+
while True:
62+
mesh.led_state()
63+
print("%d: State %s, single %s, IP %s"%(time.time(), mesh.cli('state'), mesh.cli('singleton'), mesh.ip()))
64+
65+
# check if topology changes, maybe RLOC IPv6 changed
66+
new_ip = mesh.ip()
67+
if ip != new_ip:
68+
print("IP changed from: %s to %s"%(ip, new_ip))
69+
ip = new_ip
7070

7171
# update neighbors list
7272
neigbors = mesh.neighbors_ip()
73-
print("%d Neighbors %s"%(len(neigbors), neigbors))
73+
print("%d neighbors, IPv6 list: %s"%(len(neigbors), neigbors))
7474

7575
# send PING and UDP packets to all neighbors
7676
for neighbor in neigbors:

0 commit comments

Comments
 (0)