├── README.md ├── example ├── mqttsn_publisher.py └── mqttsn_subscriber.py ├── mqttsn ├── MQTTSN.py ├── MQTTSNclient.py ├── MQTTSNinternal.py └── __init__.py └── umqttsn ├── MQTTSN.py ├── MQTTSNclient.py └── MQTTSNinternal.py /README.md: -------------------------------------------------------------------------------- 1 | # MQTT-SN client for Python 3 and Micropython 2 | 3 | **mqttsn**: Python 3 library
4 | **umqttsn**: Micropython library (Work best as frozen module)
5 | **example**: Publisher and subscriber example 6 | 7 | # Reference 8 | https://github.com/eclipse/mosquitto.rsmb 9 | -------------------------------------------------------------------------------- /example/mqttsn_publisher.py: -------------------------------------------------------------------------------- 1 | from mqttsn.MQTTSNclient import Client 2 | import struct 3 | import time 4 | import sys 5 | 6 | class Callback: 7 | 8 | def published(self, MsgId): 9 | print("Published") 10 | 11 | def connect_gateway(): 12 | try: 13 | while True: 14 | try: 15 | aclient.connect() 16 | print('Connected to gateway...') 17 | break 18 | except: 19 | print('Failed to connect to gateway, reconnecting...') 20 | time.sleep(1) 21 | except KeyboardInterrupt: 22 | print('Exiting...') 23 | sys.exit() 24 | 25 | def register_topic(): 26 | global topic1, topic2, topic3 27 | topic1 = aclient.register("topic1") 28 | print("topic1 registered.") 29 | topic2 = aclient.register("topic2") 30 | print("topic2 registered.") 31 | topic3 = aclient.register("topic3") 32 | print("topic3 registered.") 33 | 34 | aclient = Client("client_sn_pub", "10.42.0.1", port=10000) 35 | aclient.registerCallback(Callback()) 36 | connect_gateway() 37 | 38 | topic1 = None 39 | topic2 = None 40 | topic3 = None 41 | register_topic() 42 | 43 | payload1 = 'Hello World!' 44 | payload2 = struct.pack('BBB', 3,2,1) 45 | payload3 = struct.pack('d', 3.14159265359) 46 | 47 | pub_msgid = aclient.publish(topic1, payload1, qos=0) 48 | time.sleep(1) 49 | pub_msgid = aclient.publish(topic2, payload2, qos=1) 50 | time.sleep(1) 51 | pub_msgid = aclient.publish(topic3, payload3, qos=2) 52 | time.sleep(1) 53 | 54 | aclient.disconnect() 55 | print("Disconnected from gateway.") 56 | -------------------------------------------------------------------------------- /example/mqttsn_subscriber.py: -------------------------------------------------------------------------------- 1 | from mqttsn.MQTTSNclient import Client 2 | import struct 3 | import time 4 | import sys 5 | 6 | class Callback: 7 | 8 | def messageArrived(self, topicName, payload, qos, retained, msgid): 9 | print('Got msg %s from %s' % (payload, topicName)) 10 | return True 11 | 12 | def connect_gateway(): 13 | try: 14 | while True: 15 | try: 16 | aclient.connect() 17 | print('Connected to gateway...') 18 | break 19 | except: 20 | print('Failed to connect to gateway, reconnecting...') 21 | time.sleep(1) 22 | except KeyboardInterrupt: 23 | print('Exiting...') 24 | sys.exit() 25 | 26 | def subscribe_topic(): 27 | aclient.subscribe("topic3", qos=2) 28 | print("Subscribed to topic3.") 29 | aclient.subscribe("topic2", qos=1) 30 | print("Subscribed to topic2.") 31 | aclient.subscribe("topic1", qos=0) 32 | print("Subscribed to topic1.") 33 | 34 | aclient = Client("client_sn_sub", "10.42.0.1", port=10000) 35 | aclient.registerCallback(Callback()) 36 | connect_gateway() 37 | 38 | subscribe_topic() 39 | 40 | try: 41 | while True: 42 | time.sleep(1) 43 | except KeyboardInterrupt: 44 | aclient.unsubscribe('topic1') 45 | print("Unsubscribe from topic1.") 46 | aclient.unsubscribe('topic2') 47 | print("Unsubscribe from topic2.") 48 | aclient.unsubscribe('topic3') 49 | print("Unsubscribe from topic3.") 50 | aclient.disconnect() 51 | print("Disconnected from gateway.") 52 | -------------------------------------------------------------------------------- /mqttsn/MQTTSN.py: -------------------------------------------------------------------------------- 1 | """ 2 | /******************************************************************************* 3 | * Copyright (c) 2011, 2013 IBM Corp. 4 | * 5 | * All rights reserved. This program and the accompanying materials 6 | * are made available under the terms of the Eclipse Public License v1.0 7 | * and Eclipse Distribution License v1.0 which accompany this distribution. 8 | * 9 | * The Eclipse Public License is available at 10 | * http://www.eclipse.org/legal/epl-v10.html 11 | * and the Eclipse Distribution License is available at 12 | * http://www.eclipse.org/org/documents/edl-v10.php. 13 | * 14 | * Contributors: 15 | * Ian Craggs - initial API and implementation and/or initial documentation 16 | * EH Ong - port to Python 3 and Micropython 17 | *******************************************************************************/ 18 | """ 19 | 20 | import struct 21 | 22 | # Low-level protocol interface for MQTTs 23 | 24 | # Message types 25 | ADVERTISE, SEARCHGW, GWINFO, reserved, \ 26 | CONNECT, CONNACK, \ 27 | WILLTOPICREQ, WILLTOPIC, WILLMSGREQ, WILLMSG, \ 28 | REGISTER, REGACK, \ 29 | PUBLISH, PUBACK, PUBCOMP, PUBREC, PUBREL, reserved1, \ 30 | SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \ 31 | PINGREQ, PINGRESP, DISCONNECT, reserved2, \ 32 | WILLTOPICUPD, WILLTOPICRESP, WILLMSGUPD, WILLMSGRESP = range(30) 33 | 34 | packetNames = [ "ADVERTISE", "SEARCHGW", "GWINFO", "reserved", \ 35 | "CONNECT", "CONNACK", \ 36 | "WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", \ 37 | "REGISTER", "REGACK", \ 38 | "PUBLISH", "PUBACK", "PUBCOMP", "PUBREC", "PUBREL", "reserved", \ 39 | "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", \ 40 | "PINGREQ", "PINGRESP", "DISCONNECT", "reserved", \ 41 | "WILLTOPICUPD", "WILLTOPICRESP", "WILLMSGUPD", "WILLMSGRESP"] 42 | 43 | TopicIdType_Names = ["NORMAL", "PREDEFINED", "SHORT_NAME"] 44 | TOPIC_NORMAL, TOPIC_PREDEFINED, TOPIC_SHORTNAME = range(3) 45 | 46 | def writeInt16(length): 47 | return struct.pack('>H', length) 48 | 49 | def readInt16(buf): 50 | return buf[0]*256 + buf[1] 51 | 52 | def getPacket(aSocket): 53 | "receive the next packet" 54 | buf, address = aSocket.recvfrom(1000) # get the first byte fixed header 55 | if buf == "": 56 | return None 57 | 58 | length = buf[0] 59 | if length == 1: 60 | if buf == "": 61 | return None 62 | length = readInt16(buf[1:]) 63 | 64 | return buf, address 65 | 66 | def MessageType(buf): 67 | if buf[0] == 1: 68 | msgtype = buf[3] 69 | else: 70 | msgtype = buf[1] 71 | return msgtype 72 | 73 | class Flags: 74 | 75 | def __init__(self): 76 | self.DUP = False # 1 bit 77 | self.QoS = 0 # 2 bits 78 | self.Retain = False # 1 bit 79 | self.Will = False # 1 bit 80 | self.CleanSession = True # 1 bit 81 | self.TopicIdType = 0 # 2 bits 82 | 83 | def __eq__(self, flags): 84 | return self.DUP == flags.DUP and \ 85 | self.QoS == flags.QoS and \ 86 | self.Retain == flags.Retain and \ 87 | self.Will == flags.Will and \ 88 | self.CleanSession == flags.CleanSession and \ 89 | self.TopicIdType == flags.TopicIdType 90 | 91 | def __ne__(self, flags): 92 | return not self.__eq__(flags) 93 | 94 | def __str__(self): 95 | "return printable representation of our data" 96 | return '{DUP '+str(self.DUP)+ \ 97 | ", QoS "+str(self.QoS)+", Retain "+str(self.Retain) + \ 98 | ", Will "+str(self.Will)+", CleanSession "+str(self.CleanSession) + \ 99 | ", TopicIdType "+str(self.TopicIdType)+"}" 100 | 101 | def pack(self): 102 | "pack data into string buffer ready for transmission down socket" 103 | buffer = (self.DUP << 7) | (self.QoS << 5) | (self.Retain << 4) | \ 104 | (self.Will << 3) | (self.CleanSession << 2) | self.TopicIdType 105 | buffer = struct.pack('>B', buffer) 106 | #print("Flags - pack", str(bin(ord(buffer))), len(buffer)) 107 | return buffer 108 | 109 | def unpack(self, buffer): 110 | "unpack data from string buffer into separate fields" 111 | b0 = buffer[0] 112 | #print("Flags - unpack", str(bin(b0)), len(buffer), buffer) 113 | self.DUP = ((b0 >> 7) & 0x01) == 1 114 | self.QoS = (b0 >> 5) & 0x03 115 | self.Retain = ((b0 >> 4) & 0x01) == 1 116 | self.Will = ((b0 >> 3) & 0x01) == 1 117 | self.CleanSession = ((b0 >> 2) & 0x01) == 1 118 | self.TopicIdType = (b0 & 0x03) 119 | return 1 120 | 121 | class MessageHeaders: 122 | 123 | def __init__(self, aMsgType): 124 | self.Length = 0 125 | self.MsgType = aMsgType 126 | 127 | def __eq__(self, mh): 128 | return self.Length == mh.Length and self.MsgType == mh.MsgType 129 | 130 | def __str__(self): 131 | "return printable stresentation of our data" 132 | return "Length "+str(self.Length) + ", " + packetNames[self.MsgType] 133 | 134 | def pack(self, length): 135 | "pack data into string buffer ready for transmission down socket" 136 | # length does not yet include the length or msgtype bytes we are going to add 137 | buffer = self.encode(length) + struct.pack('>B', self.MsgType) 138 | return buffer 139 | 140 | def encode(self, length): 141 | self.Length = length + 2 142 | assert 2 <= self.Length <= 65535 143 | if self.Length < 256: 144 | buffer = struct.pack('>B', self.Length) 145 | #print("length", self.Length) 146 | else: 147 | self.Length += 2 148 | buffer = struct.pack('>B', 1) + writeInt16(self.Length) 149 | return buffer 150 | 151 | def unpack(self, buffer): 152 | "unpack data from string buffer into separate fields" 153 | (self.Length, bytes) = self.decode(buffer) 154 | self.MsgType = buffer[bytes] 155 | return bytes + 1 156 | 157 | def decode(self, buffer): 158 | value = buffer[0] 159 | if value > 1: 160 | bytes = 1 161 | else: 162 | value = readInt16(buffer[1:]) 163 | bytes = 3 164 | return (value, bytes) 165 | 166 | def writeUTF(aString): 167 | aString = str(aString).encode() 168 | fmt = '>%ds' % len(aString) 169 | return writeInt16(len(aString)) + struct.pack(fmt, aString) 170 | 171 | def readUTF(buffer): 172 | length = readInt16(buffer) 173 | return buffer[2:2+length] 174 | 175 | 176 | class Packets: 177 | 178 | def pack(self): 179 | return self.mh.pack(0) 180 | 181 | def __str__(self): 182 | return str(self.mh) 183 | 184 | def __eq__(self, packet): 185 | return False if packet == None else self.mh == packet.mh 186 | 187 | def __ne__(self, packet): 188 | return not self.__eq__(packet) 189 | 190 | class Advertises(Packets): 191 | 192 | def __init__(self, buffer=None): 193 | self.mh = MessageHeaders(ADVERTISE) 194 | self.GwId = 0 # 1 byte 195 | self.Duration = 0 # 2 bytes 196 | if buffer: 197 | self.unpack(buffer) 198 | 199 | def pack(self): 200 | buffer = struct.pack('>B', self.GwId) + writeInt16(self.Duration) 201 | return self.mh.pack(len(buffer)) + buffer 202 | 203 | def unpack(self, buffer): 204 | pos = self.mh.unpack(buffer) 205 | assert self.mh.MsgType == ADVERTISE 206 | self.GwId = buffer[pos] 207 | pos += 1 208 | self.Duration = readInt16(buffer[pos:]) 209 | 210 | def __str__(self): 211 | return str(self.mh) + " GwId "+str(self.GwId)+" Duration "+str(self.Duration) 212 | 213 | def __eq__(self, packet): 214 | return Packets.__eq__(self, packet) and \ 215 | self.GwId == packet.GwId and \ 216 | self.Duration == packet.Duration 217 | 218 | 219 | class SearchGWs(Packets): 220 | 221 | def __init__(self, buffer=None): 222 | self.mh = MessageHeaders(SEARCHGW) 223 | self.Radius = 0 224 | if buffer: 225 | self.unpack(buffer) 226 | 227 | def pack(self): 228 | buffer = writeInt16(self.Radius) 229 | buffer = self.mh.pack(len(buffer)) + buffer 230 | return buffer 231 | 232 | def unpack(self, buffer): 233 | pos = self.mh.unpack(buffer) 234 | assert self.mh.MsgType == SEARCHGW 235 | self.Radius = readInt16(buffer[pos:]) 236 | 237 | def __str__(self): 238 | return str(self.mh) + " Radius "+str(self.Radius) 239 | 240 | class GWInfos(Packets): 241 | 242 | def __init__(self, buffer=None): 243 | self.mh = MessageHeaders(GWINFO) 244 | self.GwId = 0 # 1 byte 245 | self.GwAdd = None # optional 246 | if buffer: 247 | self.unpack(buffer) 248 | 249 | def pack(self): 250 | buffer = struct.pack('>B', self.GwId) 251 | if self.GwAdd: 252 | self.GwAdd = str(self.GwAdd).encode() 253 | fmt = '>%ds' % len(self.GwAdd) 254 | buffer += struct.pack(fmt, self.GwAdd) 255 | buffer = self.mh.pack(len(buffer)) + buffer 256 | return buffer 257 | 258 | def unpack(self, buffer): 259 | pos = self.mh.unpack(buffer) 260 | assert self.mh.MsgType == GWINFO 261 | self.GwId = buffer[pos] 262 | pos += 1 263 | if pos >= self.mh.Length: 264 | self.GwAdd = None 265 | else: 266 | self.GwAdd = buffer[pos:] 267 | 268 | def __str__(self): 269 | buf = str(self.mh) + " Radius "+str(self.GwId) 270 | if self.GwAdd: 271 | buf += " GwAdd "+self.GwAdd 272 | return buf 273 | 274 | class Connects(Packets): 275 | 276 | def __init__(self, buffer = None): 277 | self.mh = MessageHeaders(CONNECT) 278 | self.Flags = Flags() 279 | self.ProtocolId = 1 280 | self.Duration = 30 281 | self.ClientId = "" 282 | if buffer != None: 283 | self.unpack(buffer) 284 | 285 | def pack(self): 286 | self.ClientId = str(self.ClientId).encode() 287 | fmt = '>%ds' % len(self.ClientId) 288 | buffer = self.Flags.pack() + struct.pack('>B', self.ProtocolId) + writeInt16(self.Duration) + struct.pack(fmt, self.ClientId) 289 | return self.mh.pack(len(buffer)) + buffer 290 | 291 | def unpack(self, buffer): 292 | pos = self.mh.unpack(buffer) 293 | assert self.mh.MsgType == CONNECT 294 | pos += self.Flags.unpack([buffer[pos]]) 295 | self.ProtocolId = buffer[pos] 296 | pos += 1 297 | self.Duration = readInt16(buffer[pos:]) 298 | pos += 2 299 | self.ClientId = buffer[pos:] 300 | 301 | def __str__(self): 302 | buf = str(self.mh) + ", " + str(self.Flags) + \ 303 | ", ProtocolId " + str(self.ProtocolId) + \ 304 | ", Duration " + str(self.Duration) + \ 305 | ", ClientId " + str(self.ClientId) 306 | return buf 307 | 308 | def __eq__(self, packet): 309 | rc = Packets.__eq__(self, packet) and \ 310 | self.Flags == packet.Flags and \ 311 | self.ProtocolId == packet.ProtocolId and \ 312 | self.Duration == packet.Duration and \ 313 | self.ClientId == packet.ClientId 314 | return rc 315 | 316 | 317 | class Connacks(Packets): 318 | 319 | def __init__(self, buffer = None): 320 | self.mh = MessageHeaders(CONNACK) 321 | self.ReturnCode = 0 # 1 byte 322 | if buffer != None: 323 | self.unpack(buffer) 324 | 325 | def pack(self): 326 | buffer = struct.pack('>B', self.ReturnCode) 327 | return self.mh.pack(len(buffer)) + buffer 328 | 329 | def unpack(self, buffer): 330 | pos = self.mh.unpack(buffer) 331 | assert self.mh.MsgType == CONNACK 332 | self.ReturnCode = buffer[pos] 333 | 334 | def __str__(self): 335 | return str(self.mh)+", ReturnCode "+str(self.ReturnCode) 336 | 337 | def __eq__(self, packet): 338 | return Packets.__eq__(self, packet) and \ 339 | self.ReturnCode == packet.ReturnCode 340 | 341 | 342 | class WillTopicReqs(Packets): 343 | 344 | def __init__(self, buffer = None): 345 | self.mh = MessageHeaders(WILLTOPICREQ) 346 | if buffer != None: 347 | self.unpack(buffer) 348 | 349 | def unpack(self, buffer): 350 | pos = self.mh.unpack(buffer) 351 | assert self.mh.MsgType == WILLTOPICREQ 352 | 353 | 354 | class WillTopics(Packets): 355 | 356 | def __init__(self, buffer = None): 357 | self.mh = MessageHeaders(WILLTOPIC) 358 | self.flags = Flags() 359 | self.WillTopic = "" 360 | if buffer != None: 361 | self.unpack(buffer) 362 | 363 | def pack(self): 364 | self.WillTopic = str(self.WillTopic).encode() 365 | fmt = '>%ds' % len(self.WillTopic) 366 | buffer = self.flags.pack() + struct.pack(fmt, self.WillTopic) 367 | return self.mh.pack(len(buffer)) + buffer 368 | 369 | def unpack(self, buffer): 370 | pos = self.mh.unpack(buffer) 371 | assert self.mh.MsgType == WILLTOPIC 372 | pos += self.flags.unpack(buffer[pos:]) 373 | self.WillTopic = buffer[pos:self.mh.Length] 374 | 375 | def __str__(self): 376 | return str(self.mh)+", Flags "+str(self.flags)+", WillTopic "+str(self.WillTopic) 377 | 378 | def __eq__(self, packet): 379 | return Packets.__eq__(self, packet) and \ 380 | self.flags == packet.flags and \ 381 | self.WillTopic == packet.WillTopic 382 | 383 | class WillMsgReqs(Packets): 384 | 385 | def __init__(self, buffer = None): 386 | self.mh = MessageHeaders(WILLMSGREQ) 387 | if buffer != None: 388 | self.unpack(buffer) 389 | 390 | def unpack(self, buffer): 391 | pos = self.mh.unpack(buffer) 392 | assert self.mh.MsgType == WILLMSGREQ 393 | 394 | 395 | class WillMsgs(Packets): 396 | 397 | def __init__(self, buffer = None): 398 | self.mh = MessageHeaders(WILLMSG) 399 | self.WillMsg = "" 400 | if buffer != None: 401 | self.unpack(buffer) 402 | 403 | def pack(self): 404 | self.WillMsg = str(self.WillMsg).encode() 405 | fmt = '>%ds' % len(self.WillMsg) 406 | return self.mh.pack(len(self.WillMsg)) + struct.pack(fmt, self.WillMsg) 407 | 408 | def unpack(self, buffer): 409 | pos = self.mh.unpack(buffer) 410 | assert self.mh.MsgType == WILLMSG 411 | self.WillMsg = buffer[pos:self.mh.Length] 412 | 413 | def __str__(self): 414 | return str(self.mh)+", WillMsg "+str(self.WillMsg) 415 | 416 | def __eq__(self, packet): 417 | return Packets.__eq__(self, packet) and \ 418 | self.WillMsg == packet.WillMsg 419 | 420 | class Registers(Packets): 421 | 422 | def __init__(self, buffer = None): 423 | self.mh = MessageHeaders(REGISTER) 424 | self.TopicId = 0 425 | self.MsgId = 0 426 | self.TopicName = "" 427 | if buffer != None: 428 | self.unpack(buffer) 429 | 430 | def pack(self): 431 | self.TopicName = str(self.TopicName).encode() 432 | fmt = '>%ds' % len(self.TopicName) 433 | buffer = writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack(fmt, self.TopicName) 434 | return self.mh.pack(len(buffer)) + buffer 435 | 436 | def unpack(self, buffer): 437 | pos = self.mh.unpack(buffer) 438 | assert self.mh.MsgType == REGISTER 439 | self.TopicId = readInt16(buffer[pos:]) 440 | pos += 2 441 | self.MsgId = readInt16(buffer[pos:]) 442 | pos += 2 443 | self.TopicName = buffer[pos:self.mh.Length] 444 | 445 | def __str__(self): 446 | return str(self.mh)+", TopicId "+str(self.TopicId)+", MsgId "+str(self.MsgId)+", TopicName "+str(self.TopicName) 447 | 448 | def __eq__(self, packet): 449 | return Packets.__eq__(self, packet) and \ 450 | self.TopicId == packet.TopicId and \ 451 | self.MsgId == packet.MsgId and \ 452 | self.TopicName == packet.TopicName 453 | 454 | 455 | class Regacks(Packets): 456 | 457 | def __init__(self, buffer = None): 458 | self.mh = MessageHeaders(REGACK) 459 | self.TopicId = 0 460 | self.MsgId = 0 461 | self.ReturnCode = 0 # 1 byte 462 | if buffer != None: 463 | self.unpack(buffer) 464 | 465 | def pack(self): 466 | buffer = writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack('>B', self.ReturnCode) 467 | return self.mh.pack(len(buffer)) + buffer 468 | 469 | def unpack(self, buffer): 470 | pos = self.mh.unpack(buffer) 471 | assert self.mh.MsgType == REGACK 472 | self.TopicId = readInt16(buffer[pos:]) 473 | pos += 2 474 | self.MsgId = readInt16(buffer[pos:]) 475 | pos += 2 476 | self.ReturnCode = buffer[pos] 477 | 478 | def __str__(self): 479 | return str(self.mh)+", TopicId "+str(self.TopicId)+", MsgId "+str(self.MsgId)+", ReturnCode "+str(self.ReturnCode) 480 | 481 | def __eq__(self, packet): 482 | return Packets.__eq__(self, packet) and \ 483 | self.TopicId == packet.TopicId and \ 484 | self.MsgId == packet.MsgId and \ 485 | self.ReturnCode == packet.ReturnCode 486 | 487 | 488 | class Publishes(Packets): 489 | 490 | def __init__(self, buffer = None): 491 | self.mh = MessageHeaders(PUBLISH) 492 | self.Flags = Flags() 493 | self.TopicId = 0 # 2 bytes 494 | self.TopicName = "" 495 | self.MsgId = 0 # 2 bytes 496 | self.Data = "" 497 | if buffer != None: 498 | self.unpack(buffer) 499 | 500 | def pack(self): 501 | buffer = self.Flags.pack() 502 | if self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_PREDEFINED, 3]: 503 | #print("topic id is", self.TopicId) 504 | buffer += writeInt16(self.TopicId) 505 | elif self.Flags.TopicIdType == TOPIC_SHORTNAME: 506 | topic_short = (self.TopicName + " ")[0:2] 507 | topic_short = topic_short.encode() 508 | fmt = '>%ds' % len(topic_short) 509 | buffer += topic_short 510 | if isinstance(self.Data, str): 511 | self.Data = str(self.Data).encode() 512 | fmt = '>%ds' % len(self.Data) 513 | self.Data = struct.pack(fmt, self.Data) 514 | elif isinstance(self.Data, bytes): 515 | pass 516 | buffer += writeInt16(self.MsgId) + self.Data 517 | return self.mh.pack(len(buffer)) + buffer 518 | 519 | def unpack(self, buffer): 520 | pos = self.mh.unpack(buffer) 521 | assert self.mh.MsgType == PUBLISH 522 | pos += self.Flags.unpack(buffer[pos:]) 523 | 524 | self.TopicId = 0 525 | self.TopicName = "" 526 | if self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_PREDEFINED]: 527 | self.TopicId = readInt16(buffer[pos:]) 528 | elif self.Flags.TopicIdType == TOPIC_SHORTNAME: 529 | self.TopicName = buffer[pos:pos+2] 530 | pos += 2 531 | self.MsgId = readInt16(buffer[pos:]) 532 | pos += 2 533 | self.Data = buffer[pos:self.mh.Length] 534 | 535 | def __str__(self): 536 | return str(self.mh)+", Flags "+str(self.Flags)+", TopicId "+str(self.TopicId)+", MsgId "+str(self.MsgId)+", Data "+str(self.Data) 537 | 538 | def __eq__(self, packet): 539 | return Packets.__eq__(self, packet) and \ 540 | self.Flags == packet.Flags and \ 541 | self.TopicId == packet.TopicId and \ 542 | self.MsgId == packet.MsgId and \ 543 | self.Data == packet.Data 544 | 545 | 546 | class Pubacks(Packets): 547 | 548 | def __init__(self, buffer = None): 549 | self.mh = MessageHeaders(PUBACK) 550 | self.TopicId = 0 551 | self.MsgId = 0 552 | self.ReturnCode = 0 # 1 byte 553 | if buffer != None: 554 | self.unpack(buffer) 555 | 556 | def pack(self): 557 | buffer = writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack('>B', self.ReturnCode) 558 | return self.mh.pack(len(buffer)) + buffer 559 | 560 | def unpack(self, buffer): 561 | pos = self.mh.unpack(buffer) 562 | assert self.mh.MsgType == PUBACK 563 | self.TopicId = readInt16(buffer[pos:]) 564 | pos += 2 565 | self.MsgId = readInt16(buffer[pos:]) 566 | pos += 2 567 | self.ReturnCode = buffer[pos] 568 | 569 | def __str__(self): 570 | return str(self.mh)+", TopicId "+str(self.TopicId)+" , MsgId "+str(self.MsgId)+", ReturnCode "+str(self.ReturnCode) 571 | 572 | def __eq__(self, packet): 573 | return Packets.__eq__(self, packet) and \ 574 | self.TopicId == packet.TopicId and \ 575 | self.MsgId == packet.MsgId and \ 576 | self.ReturnCode == packet.ReturnCode 577 | 578 | 579 | class Pubrecs(Packets): 580 | 581 | def __init__(self, buffer = None): 582 | self.mh = MessageHeaders(PUBREC) 583 | self.MsgId = 0 584 | if buffer != None: 585 | self.unpack(buffer) 586 | 587 | def pack(self): 588 | return self.mh.pack(2) + writeInt16(self.MsgId) 589 | 590 | def unpack(self, buffer): 591 | pos = self.mh.unpack(buffer) 592 | assert self.mh.MsgType == PUBREC 593 | self.MsgId = readInt16(buffer[pos:]) 594 | 595 | def __str__(self): 596 | return str(self.mh)+" , MsgId "+str(self.MsgId) 597 | 598 | def __eq__(self, packet): 599 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 600 | 601 | class Pubrels(Packets): 602 | 603 | def __init__(self, buffer = None): 604 | self.mh = MessageHeaders(PUBREL) 605 | self.MsgId = 0 606 | if buffer != None: 607 | self.unpack(buffer) 608 | 609 | def pack(self): 610 | return self.mh.pack(2) + writeInt16(self.MsgId) 611 | 612 | def unpack(self, buffer): 613 | pos = self.mh.unpack(buffer) 614 | assert self.mh.MsgType == PUBREL 615 | self.MsgId = readInt16(buffer[pos:]) 616 | 617 | def __str__(self): 618 | return str(self.mh)+" , MsgId "+str(self.MsgId) 619 | 620 | def __eq__(self, packet): 621 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 622 | 623 | 624 | class Pubcomps(Packets): 625 | 626 | def __init__(self, buffer = None): 627 | self.mh = MessageHeaders(PUBCOMP) 628 | self.MsgId = 0 629 | if buffer != None: 630 | self.unpack(buffer) 631 | 632 | def pack(self): 633 | return self.mh.pack(2) + writeInt16(self.MsgId) 634 | 635 | def unpack(self, buffer): 636 | pos = self.mh.unpack(buffer) 637 | assert self.mh.MsgType == PUBCOMP 638 | self.MsgId = readInt16(buffer[pos:]) 639 | 640 | def __str__(self): 641 | return str(self.mh)+" , MsgId "+str(self.MsgId) 642 | 643 | def __eq__(self, packet): 644 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 645 | 646 | 647 | class Subscribes(Packets): 648 | 649 | def __init__(self, buffer = None): 650 | self.mh = MessageHeaders(SUBSCRIBE) 651 | self.Flags = Flags() 652 | self.MsgId = 0 # 2 bytes 653 | self.TopicId = 0 # 2 bytes 654 | self.TopicName = "" 655 | if buffer != None: 656 | self.unpack(buffer) 657 | 658 | def pack(self): 659 | buffer = self.Flags.pack() + writeInt16(self.MsgId) 660 | if self.Flags.TopicIdType == TOPIC_PREDEFINED: 661 | buffer += writeInt16(self.TopicId) 662 | elif self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_SHORTNAME]: 663 | self.TopicName = str(self.TopicName).encode() 664 | fmt = '>%ds' % len(self.TopicName) 665 | buffer += struct.pack(fmt, self.TopicName) 666 | return self.mh.pack(len(buffer)) + buffer 667 | 668 | 669 | def unpack(self, buffer): 670 | pos = self.mh.unpack(buffer) 671 | assert self.mh.MsgType == SUBSCRIBE 672 | pos += self.Flags.unpack(buffer[pos:]) 673 | self.MsgId = readInt16(buffer[pos:]) 674 | pos += 2 675 | self.TopicId = 0 676 | self.TopicName = "" 677 | if self.Flags.TopicIdType == TOPIC_PREDEFINED: 678 | self.TopicId = readInt16(buffer[pos:]) 679 | elif self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_SHORTNAME]: 680 | self.TopicName = buffer[pos:pos+2] 681 | 682 | def __str__(self): 683 | buffer = str(self.mh)+", Flags "+str(self.Flags)+", MsgId "+str(self.MsgId) 684 | if self.Flags.TopicIdType == 0: 685 | buffer += ", TopicName "+str(self.TopicName) 686 | elif self.Flags.TopicIdType == 1: 687 | buffer += ", TopicId "+str(self.TopicId) 688 | elif self.Flags.TopicIdType == 2: 689 | buffer += ", TopicId "+str(self.TopicId) 690 | return buffer 691 | 692 | def __eq__(self, packet): 693 | if self.Flags.TopicIdType == 0: 694 | if packet == None: 695 | rc = False 696 | else: 697 | rc = self.TopicName == packet.TopicName 698 | else: 699 | if packet == None: 700 | rc = False 701 | else: 702 | rc = self.TopicId == packet.TopicId 703 | return Packets.__eq__(self, packet) and \ 704 | self.Flags == packet.Flags and \ 705 | self.MsgId == packet.MsgId and rc 706 | 707 | 708 | class Subacks(Packets): 709 | 710 | def __init__(self, buffer = None): 711 | self.mh = MessageHeaders(SUBACK) 712 | self.Flags = Flags() # 1 byte 713 | self.TopicId = 0 # 2 bytes 714 | self.MsgId = 0 # 2 bytes 715 | self.ReturnCode = 0 # 1 byte 716 | if buffer != None: 717 | self.unpack(buffer) 718 | 719 | def pack(self): 720 | buffer = self.Flags.pack() + writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack('>B', self.ReturnCode) 721 | return self.mh.pack(len(buffer)) + buffer 722 | 723 | def unpack(self, buffer): 724 | pos = self.mh.unpack(buffer) 725 | assert self.mh.MsgType == SUBACK 726 | pos += self.Flags.unpack(buffer[pos:]) 727 | self.TopicId = readInt16(buffer[pos:]) 728 | pos += 2 729 | self.MsgId = readInt16(buffer[pos:]) 730 | pos += 2 731 | self.ReturnCode = buffer[pos] 732 | 733 | def __str__(self): 734 | return str(self.mh)+", Flags "+str(self.Flags)+", TopicId "+str(self.TopicId)+" , MsgId "+str(self.MsgId)+", ReturnCode "+str(self.ReturnCode) 735 | 736 | def __eq__(self, packet): 737 | return Packets.__eq__(self, packet) and \ 738 | self.Flags == packet.Flags and \ 739 | self.TopicId == packet.TopicId and \ 740 | self.MsgId == packet.MsgId and \ 741 | self.ReturnCode == packet.ReturnCode 742 | 743 | 744 | class Unsubscribes(Packets): 745 | 746 | def __init__(self, buffer = None): 747 | self.mh = MessageHeaders(UNSUBSCRIBE) 748 | self.Flags = Flags() 749 | self.MsgId = 0 # 2 bytes 750 | self.TopicId = 0 # 2 bytes 751 | self.TopicName = "" 752 | if buffer != None: 753 | self.unpack(buffer) 754 | 755 | def pack(self): 756 | buffer = self.Flags.pack() + writeInt16(self.MsgId) 757 | if self.Flags.TopicIdType == 0: 758 | self.TopicName = str(self.TopicName).encode() 759 | fmt = '>%ds' % len(self.TopicName) 760 | buffer += struct.pack(fmt, self.TopicName) 761 | elif self.Flags.TopicIdType == 1: 762 | buffer += writeInt16(self.TopicId) 763 | elif self.Flags.TopicIdType == 2: 764 | self.TopicId = str(self.TopicId).encode() 765 | fmt = '>%ds' % len(self.TopicId) 766 | buffer += struct.pack(fmt, self.TopicId) 767 | return self.mh.pack(len(buffer)) + buffer 768 | 769 | def unpack(self, buffer): 770 | pos = self.mh.unpack(buffer) 771 | assert self.mh.MsgType == UNSUBSCRIBE 772 | pos += self.Flags.unpack(buffer[pos:]) 773 | self.MsgId = readInt16(buffer[pos:]) 774 | pos += 2 775 | self.TopicId = 0 776 | self.TopicName = "" 777 | if self.Flags.TopicIdType == 0: 778 | self.TopicName = buffer[pos:self.mh.Length] 779 | elif self.Flags.TopicIdType == 1: 780 | self.TopicId = readInt16(buffer[pos:]) 781 | elif self.Flags.TopicIdType == 3: 782 | self.TopicId = buffer[pos:pos+2] 783 | 784 | def __str__(self): 785 | buffer = str(self.mh)+", Flags "+str(self.Flags)+", MsgId "+str(self.MsgId) 786 | if self.Flags.TopicIdType == 0: 787 | buffer += ", TopicName "+str(self.TopicName) 788 | elif self.Flags.TopicIdType == 1: 789 | buffer += ", TopicId "+str(self.TopicId) 790 | elif self.Flags.TopicIdType == 2: 791 | buffer += ", TopicId "+str(self.TopicId) 792 | return buffer 793 | 794 | def __eq__(self, packet): 795 | return Packets.__eq__(self, packet) and \ 796 | self.Flags == packet.Flags and \ 797 | self.MsgId == packet.MsgId and \ 798 | self.TopicId == packet.TopicId and \ 799 | self.TopicName == packet.TopicName 800 | 801 | class Unsubacks(Packets): 802 | 803 | def __init__(self, buffer = None): 804 | self.mh = MessageHeaders(UNSUBACK) 805 | self.MsgId = 0 806 | if buffer != None: 807 | self.unpack(buffer) 808 | 809 | def pack(self): 810 | return self.mh.pack(2) + writeInt16(self.MsgId) 811 | 812 | def unpack(self, buffer): 813 | pos = self.mh.unpack(buffer) 814 | assert self.mh.MsgType == UNSUBACK 815 | self.MsgId = readInt16(buffer[pos:]) 816 | 817 | def __str__(self): 818 | return str(self.mh)+" , MsgId "+str(self.MsgId) 819 | 820 | def __eq__(self, packet): 821 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 822 | 823 | 824 | class Pingreqs(Packets): 825 | 826 | def __init__(self, buffer = None): 827 | self.mh = MessageHeaders(PINGREQ) 828 | self.ClientId = None 829 | if buffer != None: 830 | self.unpack(buffer) 831 | 832 | def pack(self): 833 | if self.ClientId: 834 | self.ClientId = str(self.ClientId).encode() 835 | fmt = '>%ds' % len(self.ClientId) 836 | buf = self.mh.pack(len(self.ClientId)) + struct.pack(fmt, self.ClientId) 837 | else: 838 | buf = self.mh.pack(0) 839 | return buf 840 | 841 | def unpack(self, buffer): 842 | pos = self.mh.unpack(buffer) 843 | assert self.mh.MsgType == PINGREQ 844 | self.ClientId = buffer[pos:self.mh.Length] 845 | if self.ClientId == b'': 846 | self.ClientId = None 847 | 848 | def __str__(self): 849 | buf = str(self.mh) 850 | if self.ClientId: 851 | buf += ", ClientId "+str(self.ClientId) 852 | return buf 853 | 854 | def __eq__(self, packet): 855 | return Packets.__eq__(self, packet) and \ 856 | self.ClientId == packet.ClientId 857 | 858 | 859 | class Pingresps(Packets): 860 | 861 | def __init__(self, buffer = None): 862 | self.mh = MessageHeaders(PINGRESP) 863 | if buffer != None: 864 | self.unpack(buffer) 865 | 866 | def unpack(self, buffer): 867 | pos = self.mh.unpack(buffer) 868 | assert self.mh.MsgType == PINGRESP 869 | 870 | class Disconnects(Packets): 871 | 872 | def __init__(self, buffer = None): 873 | self.mh = MessageHeaders(DISCONNECT) 874 | self.Duration = None 875 | if buffer != None: 876 | self.unpack(buffer) 877 | 878 | def pack(self): 879 | if self.Duration: 880 | buf = self.mh.pack(2) + writeInt16(self.Duration) 881 | else: 882 | buf = self.mh.pack(0) 883 | return buf 884 | 885 | def unpack(self, buffer): 886 | pos = self.mh.unpack(buffer) 887 | assert self.mh.MsgType == DISCONNECT 888 | buf = buffer[pos:self.mh.Length] 889 | if buf == b'': 890 | self.Duration = None 891 | else: 892 | self.Duration = readInt16(buffer[pos:]) 893 | 894 | def __str__(self): 895 | buf = str(self.mh) 896 | if self.Duration: 897 | buf += ", Duration "+str(self.Duration) 898 | return buf 899 | 900 | def __eq__(self, packet): 901 | return Packets.__eq__(self, packet) and \ 902 | self.Duration == packet.Duration 903 | 904 | class WillTopicUpds(Packets): 905 | 906 | def __init__(self, buffer = None): 907 | self.mh = MessageHeaders(WILLTOPICUPD) 908 | self.flags = Flags() 909 | self.WillTopic = "" 910 | if buffer != None: 911 | self.unpack(buffer) 912 | 913 | def pack(self): 914 | self.WillTopic = str(self.WillTopic).encode() 915 | fmt = '>%ds' % len(self.WillTopic) 916 | buffer = self.flags.pack() + struct.pack(fmt, self.WillTopic) 917 | return self.mh.pack(len(buffer)) + buffer 918 | 919 | def unpack(self, buffer): 920 | pos = self.mh.unpack(buffer) 921 | assert self.mh.MsgType == WILLTOPICUPD 922 | pos += self.flags.unpack(buffer[pos:]) 923 | self.WillTopic = buffer[pos:self.mh.Length] 924 | 925 | def __str__(self): 926 | return str(self.mh)+", Flags "+str(self.flags)+", WillTopic "+str(self.WillTopic) 927 | 928 | def __eq__(self, packet): 929 | return Packets.__eq__(self, packet) and \ 930 | self.flags == packet.flags and \ 931 | self.WillTopic == packet.WillTopic 932 | 933 | class WillMsgUpds(Packets): 934 | 935 | def __init__(self, buffer = None): 936 | self.mh = MessageHeaders(WILLMSGUPD) 937 | self.WillMsg = "" 938 | if buffer != None: 939 | self.unpack(buffer) 940 | 941 | def pack(self): 942 | self.WillMsg = str(self.WillMsg).encode() 943 | fmt = '>%ds' % len(self.WillMsg) 944 | return self.mh.pack(len(self.WillMsg)) + struct.pack(fmt, self.WillMsg) 945 | 946 | def unpack(self, buffer): 947 | pos = self.mh.unpack(buffer) 948 | assert self.mh.MsgType == WILLMSGUPD 949 | self.WillMsg = buffer[pos:self.mh.Length] 950 | 951 | def __str__(self): 952 | return str(self.mh)+", WillMsg "+str(self.WillMsg) 953 | 954 | def __eq__(self, packet): 955 | return Packets.__eq__(self, packet) and \ 956 | self.WillMsg == packet.WillMsg 957 | 958 | class WillTopicResps(Packets): 959 | 960 | def __init__(self, buffer = None): 961 | self.mh = MessageHeaders(WILLTOPICRESP) 962 | self.ReturnCode = 0 963 | if buffer != None: 964 | self.unpack(buffer) 965 | 966 | def pack(self): 967 | buffer = writeInt16(self.ReturnCode) 968 | return self.mh.pack(len(buffer)) + buffer 969 | 970 | def unpack(self, buffer): 971 | pos = self.mh.unpack(buffer) 972 | assert self.mh.MsgType == WILLTOPICRESP 973 | self.ReturnCode = readInt16(buffer[pos:]) 974 | 975 | def __str__(self): 976 | return str(self.mh)+", ReturnCode "+str(self.ReturnCode) 977 | 978 | def __eq__(self, packet): 979 | return Packets.__eq__(self, packet) and \ 980 | self.ReturnCode == packet.ReturnCode 981 | 982 | class WillMsgResps(Packets): 983 | 984 | def __init__(self, buffer = None): 985 | self.mh = MessageHeaders(WILLMSGRESP) 986 | self.ReturnCode = 0 987 | if buffer != None: 988 | self.unpack(buffer) 989 | 990 | def pack(self): 991 | buffer = writeInt16(self.ReturnCode) 992 | return self.mh.pack(len(buffer)) + buffer 993 | 994 | def unpack(self, buffer): 995 | pos = self.mh.unpack(buffer) 996 | assert self.mh.MsgType == WILLMSGRESP 997 | self.returnCode = readInt16(buffer[pos:]) 998 | 999 | def __str__(self): 1000 | return str(self.mh)+", ReturnCode "+str(self.ReturnCode) 1001 | 1002 | def __eq__(self, packet): 1003 | return Packets.__eq__(self, packet) and \ 1004 | self.ReturnCode == packet.ReturnCode 1005 | 1006 | objects = [Advertises, SearchGWs, GWInfos, None, 1007 | Connects, Connacks, 1008 | WillTopicReqs, WillTopics, WillMsgReqs, WillMsgs, 1009 | Registers, Regacks, 1010 | Publishes, Pubacks, Pubcomps, Pubrecs, Pubrels, None, 1011 | Subscribes, Subacks, Unsubscribes, Unsubacks, 1012 | Pingreqs, Pingresps, Disconnects, None, 1013 | WillTopicUpds, WillTopicResps, WillMsgUpds, WillMsgResps] 1014 | 1015 | def unpackPacket(msg): 1016 | (buffer, address) = msg 1017 | if MessageType(buffer) != None: 1018 | packet = objects[MessageType(buffer)]() 1019 | packet.unpack(buffer) 1020 | else: 1021 | packet = None 1022 | return packet, address 1023 | 1024 | if __name__ == "__main__": 1025 | print("Object string representations") 1026 | for o in objects: 1027 | if o: 1028 | print(o()) 1029 | 1030 | print("\nComparisons") 1031 | for o in [Flags] + objects: 1032 | if o: 1033 | o1 = o() 1034 | o2 = o() 1035 | o2.unpack(o1.pack()) 1036 | if o1 != o2: 1037 | print("error! ", str(o1.mh) if hasattr(o1, "mh") else o1.__class__.__name__) 1038 | print(str(o1)) 1039 | print(str(o2)) 1040 | else: 1041 | print("ok ", str(o1.mh) if hasattr(o1, "mh") else o1.__class__.__name__) 1042 | -------------------------------------------------------------------------------- /mqttsn/MQTTSNclient.py: -------------------------------------------------------------------------------- 1 | """ 2 | /******************************************************************************* 3 | * Copyright (c) 2011, 2013 IBM Corp. 4 | * 5 | * All rights reserved. This program and the accompanying materials 6 | * are made available under the terms of the Eclipse Public License v1.0 7 | * and Eclipse Distribution License v1.0 which accompany this distribution. 8 | * 9 | * The Eclipse Public License is available at 10 | * http://www.eclipse.org/legal/epl-v10.html 11 | * and the Eclipse Distribution License is available at 12 | * http://www.eclipse.org/org/documents/edl-v10.php. 13 | * 14 | * Contributors: 15 | * Ian Craggs - initial API and implementation and/or initial documentation 16 | * EH Ong - port to Python 3 and Micropython 17 | *******************************************************************************/ 18 | """ 19 | 20 | import mqttsn.MQTTSN as MQTTSN 21 | import mqttsn.MQTTSNinternal as MQTTSNinternal 22 | import socket, time, _thread, sys, struct, queue 23 | 24 | 25 | class Callback: 26 | 27 | def __init__(self): 28 | self.events = [] 29 | 30 | def connectionLost(self, cause): 31 | print("default connectionLost", cause) 32 | self.events.append("disconnected") 33 | 34 | def messageArrived(self, topicName, payload, qos, retained, msgid): 35 | print("default publishArrived", topicName, payload, qos, retained, msgid) 36 | return True 37 | 38 | def deliveryComplete(self, msgid): 39 | print("default deliveryComplete") 40 | 41 | def advertise(self, address, gwid, duration): 42 | print("advertise", address, gwid, duration) 43 | 44 | class TopicMap: 45 | 46 | def __init__(self): 47 | self.registered = {} 48 | 49 | def register(self, topicId, topicName): 50 | self.registered[topicId] = topicName 51 | 52 | class Client: 53 | 54 | def __init__(self, clientid, host="localhost", port=1883): 55 | self.clientid = clientid 56 | self.host = host 57 | self.port = port 58 | self.msgid = 1 59 | self.callback = None 60 | self.__receiver = None 61 | self.topicmap = TopicMap() 62 | self.queue = queue.Queue() 63 | 64 | def start(self): 65 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 66 | self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 67 | self.sock.bind((self.host, self.port)) 68 | mreq = struct.pack("4sl", socket.inet_aton(self.host), socket.INADDR_ANY) 69 | 70 | self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 71 | 72 | self.startReceiver() 73 | 74 | def stop(self): 75 | self.stopReceiver() 76 | 77 | def __nextMsgid(self): 78 | def getWrappedMsgid(): 79 | id = self.msgid + 1 80 | if id == 65535: 81 | id = 1 82 | return id 83 | 84 | if len(self.__receiver.outMsgs) >= 65535: 85 | raise "No slots left!!" 86 | else: 87 | self.msgid = getWrappedMsgid() 88 | while self.msgid in self.__receiver.outMsgs: 89 | self.msgid = getWrappedMsgid() 90 | return self.msgid 91 | 92 | 93 | def registerCallback(self, callback): 94 | self.callback = callback 95 | 96 | 97 | def connect(self, cleansession=True): 98 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 99 | self.sock.settimeout(5.0) 100 | 101 | self.sock.connect((self.host, self.port)) 102 | 103 | connect = MQTTSN.Connects() 104 | connect.ClientId = self.clientid 105 | connect.CleanSession = cleansession 106 | connect.KeepAliveTimer = 0 107 | self.sock.send(connect.pack()) 108 | 109 | response, address = MQTTSN.unpackPacket(MQTTSN.getPacket(self.sock)) 110 | assert response.mh.MsgType == MQTTSN.CONNACK 111 | 112 | self.startReceiver() 113 | 114 | 115 | def startReceiver(self): 116 | self.__receiver = MQTTSNinternal.Receivers(self.sock) 117 | if self.callback: 118 | id = _thread.start_new_thread(self.__receiver, (self.callback,self.topicmap,self.queue,)) 119 | 120 | 121 | def waitfor(self, msgType, msgId=None): 122 | if self.__receiver: 123 | msg = self.__receiver.waitfor(msgType, msgId) 124 | else: 125 | msg = self.__receiver.receive() 126 | while msg.mh.MsgType != msgType and (msgId == None or msgId == msg.MsgId): 127 | msg = self.__receiver.receive() 128 | return msg 129 | 130 | 131 | def subscribe(self, topic, qos=0): 132 | subscribe = MQTTSN.Subscribes() 133 | subscribe.MsgId = self.__nextMsgid() 134 | if isinstance(topic, str): 135 | subscribe.TopicName = topic 136 | if len(topic) > 2: 137 | subscribe.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 138 | else: 139 | subscribe.Flags.TopicIdType = MQTTSN.TOPIC_SHORTNAME 140 | else: 141 | subscribe.TopicId = topic # should be int 142 | subscribe.Flags.TopicIdType = MQTTSN.TOPIC_PREDEFINED 143 | subscribe.Flags.QoS = qos 144 | if self.__receiver: 145 | self.__receiver.lookfor(MQTTSN.SUBACK) 146 | self.sock.send(subscribe.pack()) 147 | msg = self.waitfor(MQTTSN.SUBACK, subscribe.MsgId) 148 | self.topicmap.register(msg.TopicId, topic) 149 | return msg.ReturnCode, msg.TopicId 150 | 151 | 152 | def unsubscribe(self, topics): 153 | unsubscribe = MQTTSN.Unsubscribes() 154 | unsubscribe.MsgId = self.__nextMsgid() 155 | unsubscribe.data = topics 156 | if self.__receiver: 157 | self.__receiver.lookfor(MQTTSN.UNSUBACK) 158 | self.sock.send(unsubscribe.pack()) 159 | msg = self.waitfor(MQTTSN.UNSUBACK, unsubscribe.MsgId) 160 | 161 | 162 | def register(self, topicName): 163 | register = MQTTSN.Registers() 164 | register.TopicName = topicName 165 | if self.__receiver: 166 | self.__receiver.lookfor(MQTTSN.REGACK) 167 | self.sock.send(register.pack()) 168 | msg = self.waitfor(MQTTSN.REGACK, register.MsgId) 169 | self.topicmap.register(msg.TopicId, topicName) 170 | return msg.TopicId 171 | 172 | 173 | def publish(self, topic, payload, qos=0, retained=False): 174 | if isinstance(payload, str) or isinstance(payload, bytes): 175 | pass 176 | else: 177 | raise TypeError('Payload must be str or bytes.') 178 | publish = MQTTSN.Publishes() 179 | publish.Flags.QoS = qos 180 | publish.Flags.Retain = retained 181 | if isinstance(topic, str): 182 | publish.Flags.TopicIdType = MQTTSN.TOPIC_SHORTNAME 183 | publish.TopicName = topic 184 | else: 185 | publish.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 186 | publish.TopicId = topic 187 | if qos in [-1, 0]: 188 | publish.MsgId = 0 189 | else: 190 | publish.MsgId = self.__nextMsgid() 191 | #print("MsgId", publish.MsgId) 192 | self.__receiver.outMsgs[publish.MsgId] = publish 193 | publish.Data = payload 194 | self.sock.send(publish.pack()) 195 | return publish.MsgId 196 | 197 | 198 | def disconnect(self): 199 | disconnect = MQTTSN.Disconnects() 200 | if self.__receiver: 201 | self.__receiver.lookfor(MQTTSN.DISCONNECT) 202 | self.sock.send(disconnect.pack()) 203 | msg = self.waitfor(MQTTSN.DISCONNECT) 204 | self.stopReceiver() 205 | 206 | 207 | def stopReceiver(self): 208 | self.sock.close() # this will stop the receiver too 209 | ## assert self.__receiver.inMsgs == {} 210 | ## assert self.__receiver.outMsgs == {} 211 | self.__receiver = None 212 | 213 | def receive(self): 214 | return self.__receiver.receive() 215 | 216 | 217 | def publish(topic, payload, retained=False, port=1883, host="localhost"): 218 | publish = MQTTSN.Publishes() 219 | publish.Flags.QoS = 3 220 | publish.Flags.Retain = retained 221 | if isinstance(payload, str): 222 | pass 223 | elif isinstance(payload, bytes): 224 | payload = payload.decode() 225 | if isinstance(topic, str): 226 | if len(topic) > 2: 227 | publish.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 228 | publish.TopicId = len(topic) 229 | payload = topic + payload 230 | else: 231 | publish.Flags.TopicIdType = MQTTSN.TOPIC_SHORTNAME 232 | publish.TopicName = topic 233 | else: 234 | publish.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 235 | publish.TopicId = topic 236 | publish.MsgId = 0 237 | #print("payload", payload) 238 | publish.Data = payload 239 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 240 | sock.sendto(publish.pack(), (host, port)) 241 | sock.close() 242 | return 243 | 244 | 245 | if __name__ == "__main__": 246 | 247 | """ 248 | mclient = Client("myclientid", host="225.0.18.83", port=1883) 249 | mclient.registerCallback(Callback()) 250 | mclient.start() 251 | 252 | publish("long topic name", "qos -1 start", port=1884) 253 | 254 | callback = Callback() 255 | 256 | aclient = Client("myclientid", port=1884) 257 | aclient.registerCallback(callback) 258 | 259 | aclient.connect() 260 | aclient.disconnect() 261 | 262 | aclient.connect() 263 | aclient.subscribe("k ", 2) 264 | aclient.subscribe("jkjkjkjkj", 2) 265 | aclient.publish("k ", "qos 0") 266 | aclient.publish("k ", "qos 1", 1) 267 | aclient.publish("jkjkjkjkj", "qos 2", 2) 268 | topicid = aclient.register("jkjkjkjkj") 269 | #time.sleep(1.0) 270 | aclient.publish(topicid, "qos 2 - registered topic id", 2) 271 | #time.sleep(1.0) 272 | aclient.disconnect() 273 | publish("long topic name", "qos -1 end", port=1884) 274 | 275 | time.sleep(30) 276 | mclient.stop() 277 | """ 278 | 279 | 280 | aclient = Client("linh", port=1885) 281 | aclient.registerCallback(Callback()) 282 | aclient.connect() 283 | 284 | rc, topic1 = aclient.subscribe("topic1") 285 | print("topic id for topic1 is", topic1) 286 | rc, topic2 = aclient.subscribe("topic2") 287 | print("topic id for topic2 is", topic2) 288 | aclient.publish(topic1, "aaaa", qos=0) 289 | aclient.publish(topic2, "bbbb", qos=0) 290 | aclient.unsubscribe("topic1") 291 | aclient.publish(topic2, "bbbb", qos=0) 292 | aclient.publish(topic1, "aaaa", qos=0) 293 | aclient.disconnect() 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /mqttsn/MQTTSNinternal.py: -------------------------------------------------------------------------------- 1 | """ 2 | /******************************************************************************* 3 | * Copyright (c) 2011, 2013 IBM Corp. 4 | * 5 | * All rights reserved. This program and the accompanying materials 6 | * are made available under the terms of the Eclipse Public License v1.0 7 | * and Eclipse Distribution License v1.0 which accompany this distribution. 8 | * 9 | * The Eclipse Public License is available at 10 | * http://www.eclipse.org/legal/epl-v10.html 11 | * and the Eclipse Distribution License is available at 12 | * http://www.eclipse.org/org/documents/edl-v10.php. 13 | * 14 | * Contributors: 15 | * Ian Craggs - initial API and implementation and/or initial documentation 16 | * EH Ong - port to Python 3 and Micropython 17 | *******************************************************************************/ 18 | """ 19 | 20 | import mqttsn.MQTTSN as MQTTSN 21 | import time, sys, socket 22 | 23 | debug = False 24 | 25 | class Receivers: 26 | 27 | def __init__(self, socket): 28 | #print("initializing receiver") 29 | self.socket = socket 30 | self.connected = False 31 | self.observe = None 32 | self.observed = [] 33 | 34 | self.inMsgs = {} 35 | self.outMsgs = {} 36 | 37 | self.puback = MQTTSN.Pubacks() 38 | self.pubrec = MQTTSN.Pubrecs() 39 | self.pubrel = MQTTSN.Pubrels() 40 | self.pubcomp = MQTTSN.Pubcomps() 41 | 42 | def lookfor(self, msgType): 43 | self.observe = msgType 44 | 45 | def waitfor(self, msgType, msgId=None): 46 | msg = None 47 | count = 0 48 | while True: 49 | while len(self.observed) > 0: 50 | msg = self.observed.pop(0) 51 | if msg.mh.MsgType == msgType and (msgId == None or msg.MsgId == msgId): 52 | break 53 | else: 54 | msg = None 55 | if msg != None: 56 | break 57 | time.sleep(0.2) 58 | count += 1 59 | if count == 25: 60 | msg = None 61 | break 62 | self.observe = None 63 | return msg 64 | 65 | def receive(self, topicmap, callback=None): 66 | packet = None 67 | try: 68 | packet, address = MQTTSN.unpackPacket(MQTTSN.getPacket(self.socket)) 69 | except: 70 | if sys.exc_info()[0] != socket.timeout: 71 | #print("unexpected exception", sys.exc_info()) 72 | raise sys.exc_info() 73 | if packet == None: 74 | time.sleep(0.1) 75 | return 76 | elif debug: 77 | print(packet) 78 | 79 | if self.observe == packet.mh.MsgType: 80 | #print("observed", packet) 81 | self.observed.append(packet) 82 | 83 | elif packet.mh.MsgType == MQTTSN.ADVERTISE: 84 | if hasattr(callback, "advertise"): 85 | callback.advertise(address, packet.GwId, packet.Duration) 86 | 87 | elif packet.mh.MsgType == MQTTSN.REGISTER: 88 | topicmap.register(packet.TopicId, packet.TopicName) 89 | 90 | elif packet.mh.MsgType == MQTTSN.PUBACK: 91 | "check if we are expecting a puback" 92 | if packet.MsgId in self.outMsgs and \ 93 | self.outMsgs[packet.MsgId].Flags.QoS == 1: 94 | del self.outMsgs[packet.MsgId] 95 | if hasattr(callback, "published"): 96 | callback.published(packet.MsgId) 97 | else: 98 | raise Exception("No QoS 1 message with message id "+str(packet.MsgId)+" sent") 99 | 100 | elif packet.mh.MsgType == MQTTSN.PUBREC: 101 | if packet.MsgId in self.outMsgs: 102 | self.pubrel.MsgId = packet.MsgId 103 | self.socket.send(self.pubrel.pack()) 104 | else: 105 | raise Exception("PUBREC received for unknown msg id "+ \ 106 | str(packet.MsgId)) 107 | 108 | elif packet.mh.MsgType == MQTTSN.PUBREL: 109 | "release QOS 2 publication to client, & send PUBCOMP" 110 | msgid = packet.MsgId 111 | if packet.MsgId not in self.inMsgs: 112 | pass # what should we do here? 113 | else: 114 | pub = self.inMsgs[packet.MsgId] 115 | topicname = topicmap.registered[pub.TopicId] 116 | if callback == None or \ 117 | callback.messageArrived(topicname, pub.Data, 2, pub.Flags.Retain, pub.MsgId): 118 | del self.inMsgs[packet.MsgId] 119 | self.pubcomp.MsgId = packet.MsgId 120 | self.socket.send(self.pubcomp.pack()) 121 | if callback == None: 122 | return (topicname, pub.Data, 2, pub.Flags.Retain, pub.MsgId) 123 | 124 | elif packet.mh.MsgType == MQTTSN.PUBCOMP: 125 | "finished with this message id" 126 | if packet.MsgId in self.outMsgs: 127 | del self.outMsgs[packet.MsgId] 128 | if hasattr(callback, "published"): 129 | callback.published(packet.MsgId) 130 | else: 131 | raise Exception("PUBCOMP received for unknown msg id "+ \ 132 | str(packet.MsgId)) 133 | 134 | elif packet.mh.MsgType == MQTTSN.PUBLISH: 135 | "finished with this message id" 136 | if packet.Flags.QoS in [0, 3]: 137 | qos = packet.Flags.QoS 138 | topicname = topicmap.registered[packet.TopicId] 139 | data = packet.Data 140 | if qos == 3: 141 | qos = -1 142 | if packet.Flags.TopicIdType == MQTTSN.TOPICID: 143 | topicname = packet.Data[:packet.TopicId] 144 | data = packet.Data[packet.TopicId:] 145 | if callback == None: 146 | return (topicname, data, qos, packet.Flags.Retain, packet.MsgId) 147 | else: 148 | callback.messageArrived(topicname, data, qos, packet.Flags.Retain, packet.MsgId) 149 | elif packet.Flags.QoS == 1: 150 | topicname = topicmap.registered[packet.TopicId] 151 | if callback == None: 152 | return (topicname, packet.Data, 1, 153 | packet.Flags.Retain, packet.MsgId) 154 | else: 155 | if callback.messageArrived(topicname, packet.Data, 1, 156 | packet.Flags.Retain, packet.MsgId): 157 | self.puback.MsgId = packet.MsgId 158 | self.socket.send(self.puback.pack()) 159 | elif packet.Flags.QoS == 2: 160 | self.inMsgs[packet.MsgId] = packet 161 | self.pubrec.MsgId = packet.MsgId 162 | self.socket.send(self.pubrec.pack()) 163 | 164 | else: 165 | raise Exception("Unexpected packet"+str(packet)) 166 | return packet 167 | 168 | def __call__(self, callback, topicmap, queue): 169 | try: 170 | while True: 171 | self.receive(topicmap, callback) 172 | except: 173 | queue.put(sys.exc_info()) 174 | if sys.exc_info()[0] != socket.error: 175 | #print("unexpected exception", sys.exc_info()) 176 | pass 177 | -------------------------------------------------------------------------------- /mqttsn/__init__.py: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /umqttsn/MQTTSN.py: -------------------------------------------------------------------------------- 1 | """ 2 | /******************************************************************************* 3 | * Copyright (c) 2011, 2013 IBM Corp. 4 | * 5 | * All rights reserved. This program and the accompanying materials 6 | * are made available under the terms of the Eclipse Public License v1.0 7 | * and Eclipse Distribution License v1.0 which accompany this distribution. 8 | * 9 | * The Eclipse Public License is available at 10 | * http://www.eclipse.org/legal/epl-v10.html 11 | * and the Eclipse Distribution License is available at 12 | * http://www.eclipse.org/org/documents/edl-v10.php. 13 | * 14 | * Contributors: 15 | * Ian Craggs - initial API and implementation and/or initial documentation 16 | * EH Ong - port to Python 3 and Micropython 17 | *******************************************************************************/ 18 | """ 19 | 20 | import struct 21 | 22 | # Low-level protocol interface for MQTTs 23 | 24 | # Message types 25 | ADVERTISE, SEARCHGW, GWINFO, reserved, \ 26 | CONNECT, CONNACK, \ 27 | WILLTOPICREQ, WILLTOPIC, WILLMSGREQ, WILLMSG, \ 28 | REGISTER, REGACK, \ 29 | PUBLISH, PUBACK, PUBCOMP, PUBREC, PUBREL, reserved1, \ 30 | SUBSCRIBE, SUBACK, UNSUBSCRIBE, UNSUBACK, \ 31 | PINGREQ, PINGRESP, DISCONNECT, reserved2, \ 32 | WILLTOPICUPD, WILLTOPICRESP, WILLMSGUPD, WILLMSGRESP = range(30) 33 | 34 | packetNames = [ "ADVERTISE", "SEARCHGW", "GWINFO", "reserved", \ 35 | "CONNECT", "CONNACK", \ 36 | "WILLTOPICREQ", "WILLTOPIC", "WILLMSGREQ", "WILLMSG", \ 37 | "REGISTER", "REGACK", \ 38 | "PUBLISH", "PUBACK", "PUBCOMP", "PUBREC", "PUBREL", "reserved", \ 39 | "SUBSCRIBE", "SUBACK", "UNSUBSCRIBE", "UNSUBACK", \ 40 | "PINGREQ", "PINGRESP", "DISCONNECT", "reserved", \ 41 | "WILLTOPICUPD", "WILLTOPICRESP", "WILLMSGUPD", "WILLMSGRESP"] 42 | 43 | TopicIdType_Names = ["NORMAL", "PREDEFINED", "SHORT_NAME"] 44 | TOPIC_NORMAL, TOPIC_PREDEFINED, TOPIC_SHORTNAME = range(3) 45 | 46 | def writeInt16(length): 47 | return struct.pack('>H', length) 48 | 49 | def readInt16(buf): 50 | return buf[0]*256 + buf[1] 51 | 52 | def getPacket(aSocket): 53 | "receive the next packet" 54 | buf, address = aSocket.recvfrom(1000) # get the first byte fixed header 55 | if buf == "": 56 | return None 57 | 58 | length = buf[0] 59 | if length == 1: 60 | if buf == "": 61 | return None 62 | length = readInt16(buf[1:]) 63 | 64 | return buf, address 65 | 66 | def MessageType(buf): 67 | if buf[0] == 1: 68 | msgtype = buf[3] 69 | else: 70 | msgtype = buf[1] 71 | return msgtype 72 | 73 | class Flags: 74 | 75 | def __init__(self): 76 | self.DUP = False # 1 bit 77 | self.QoS = 0 # 2 bits 78 | self.Retain = False # 1 bit 79 | self.Will = False # 1 bit 80 | self.CleanSession = True # 1 bit 81 | self.TopicIdType = 0 # 2 bits 82 | 83 | def __eq__(self, flags): 84 | return self.DUP == flags.DUP and \ 85 | self.QoS == flags.QoS and \ 86 | self.Retain == flags.Retain and \ 87 | self.Will == flags.Will and \ 88 | self.CleanSession == flags.CleanSession and \ 89 | self.TopicIdType == flags.TopicIdType 90 | 91 | def __ne__(self, flags): 92 | return not self.__eq__(flags) 93 | 94 | def __str__(self): 95 | "return printable representation of our data" 96 | return '{DUP '+str(self.DUP)+ \ 97 | ", QoS "+str(self.QoS)+", Retain "+str(self.Retain) + \ 98 | ", Will "+str(self.Will)+", CleanSession "+str(self.CleanSession) + \ 99 | ", TopicIdType "+str(self.TopicIdType)+"}" 100 | 101 | def pack(self): 102 | "pack data into string buffer ready for transmission down socket" 103 | buffer = (self.DUP << 7) | (self.QoS << 5) | (self.Retain << 4) | \ 104 | (self.Will << 3) | (self.CleanSession << 2) | self.TopicIdType 105 | buffer = struct.pack('>B', buffer) 106 | #print("Flags - pack", str(bin(ord(buffer))), len(buffer)) 107 | return buffer 108 | 109 | def unpack(self, buffer): 110 | "unpack data from string buffer into separate fields" 111 | b0 = buffer[0] 112 | #print("Flags - unpack", str(bin(b0)), len(buffer), buffer) 113 | self.DUP = ((b0 >> 7) & 0x01) == 1 114 | self.QoS = (b0 >> 5) & 0x03 115 | self.Retain = ((b0 >> 4) & 0x01) == 1 116 | self.Will = ((b0 >> 3) & 0x01) == 1 117 | self.CleanSession = ((b0 >> 2) & 0x01) == 1 118 | self.TopicIdType = (b0 & 0x03) 119 | return 1 120 | 121 | class MessageHeaders: 122 | 123 | def __init__(self, aMsgType): 124 | self.Length = 0 125 | self.MsgType = aMsgType 126 | 127 | def __eq__(self, mh): 128 | return self.Length == mh.Length and self.MsgType == mh.MsgType 129 | 130 | def __str__(self): 131 | "return printable stresentation of our data" 132 | return "Length "+str(self.Length) + ", " + packetNames[self.MsgType] 133 | 134 | def pack(self, length): 135 | "pack data into string buffer ready for transmission down socket" 136 | # length does not yet include the length or msgtype bytes we are going to add 137 | buffer = self.encode(length) + struct.pack('>B', self.MsgType) 138 | return buffer 139 | 140 | def encode(self, length): 141 | self.Length = length + 2 142 | assert 2 <= self.Length <= 65535 143 | if self.Length < 256: 144 | buffer = struct.pack('>B', self.Length) 145 | #print("length", self.Length) 146 | else: 147 | self.Length += 2 148 | buffer = struct.pack('>B', 1) + writeInt16(self.Length) 149 | return buffer 150 | 151 | def unpack(self, buffer): 152 | "unpack data from string buffer into separate fields" 153 | (self.Length, bytes) = self.decode(buffer) 154 | self.MsgType = buffer[bytes] 155 | return bytes + 1 156 | 157 | def decode(self, buffer): 158 | value = buffer[0] 159 | if value > 1: 160 | bytes = 1 161 | else: 162 | value = readInt16(buffer[1:]) 163 | bytes = 3 164 | return (value, bytes) 165 | 166 | def writeUTF(aString): 167 | aString = str(aString).encode() 168 | fmt = '>%ds' % len(aString) 169 | return writeInt16(len(aString)) + struct.pack(fmt, aString) 170 | 171 | def readUTF(buffer): 172 | length = readInt16(buffer) 173 | return buffer[2:2+length] 174 | 175 | 176 | class Packets: 177 | 178 | def pack(self): 179 | return self.mh.pack(0) 180 | 181 | def __str__(self): 182 | return str(self.mh) 183 | 184 | def __eq__(self, packet): 185 | return False if packet == None else self.mh == packet.mh 186 | 187 | def __ne__(self, packet): 188 | return not self.__eq__(packet) 189 | 190 | class Advertises(Packets): 191 | 192 | def __init__(self, buffer=None): 193 | self.mh = MessageHeaders(ADVERTISE) 194 | self.GwId = 0 # 1 byte 195 | self.Duration = 0 # 2 bytes 196 | if buffer: 197 | self.unpack(buffer) 198 | 199 | def pack(self): 200 | buffer = struct.pack('>B', self.GwId) + writeInt16(self.Duration) 201 | return self.mh.pack(len(buffer)) + buffer 202 | 203 | def unpack(self, buffer): 204 | pos = self.mh.unpack(buffer) 205 | assert self.mh.MsgType == ADVERTISE 206 | self.GwId = buffer[pos] 207 | pos += 1 208 | self.Duration = readInt16(buffer[pos:]) 209 | 210 | def __str__(self): 211 | return str(self.mh) + " GwId "+str(self.GwId)+" Duration "+str(self.Duration) 212 | 213 | def __eq__(self, packet): 214 | return Packets.__eq__(self, packet) and \ 215 | self.GwId == packet.GwId and \ 216 | self.Duration == packet.Duration 217 | 218 | 219 | class SearchGWs(Packets): 220 | 221 | def __init__(self, buffer=None): 222 | self.mh = MessageHeaders(SEARCHGW) 223 | self.Radius = 0 224 | if buffer: 225 | self.unpack(buffer) 226 | 227 | def pack(self): 228 | buffer = writeInt16(self.Radius) 229 | buffer = self.mh.pack(len(buffer)) + buffer 230 | return buffer 231 | 232 | def unpack(self, buffer): 233 | pos = self.mh.unpack(buffer) 234 | assert self.mh.MsgType == SEARCHGW 235 | self.Radius = readInt16(buffer[pos:]) 236 | 237 | def __str__(self): 238 | return str(self.mh) + " Radius "+str(self.Radius) 239 | 240 | class GWInfos(Packets): 241 | 242 | def __init__(self, buffer=None): 243 | self.mh = MessageHeaders(GWINFO) 244 | self.GwId = 0 # 1 byte 245 | self.GwAdd = None # optional 246 | if buffer: 247 | self.unpack(buffer) 248 | 249 | def pack(self): 250 | buffer = struct.pack('>B', self.GwId) 251 | if self.GwAdd: 252 | self.GwAdd = str(self.GwAdd).encode() 253 | fmt = '>%ds' % len(self.GwAdd) 254 | buffer += struct.pack(fmt, self.GwAdd) 255 | buffer = self.mh.pack(len(buffer)) + buffer 256 | return buffer 257 | 258 | def unpack(self, buffer): 259 | pos = self.mh.unpack(buffer) 260 | assert self.mh.MsgType == GWINFO 261 | self.GwId = buffer[pos] 262 | pos += 1 263 | if pos >= self.mh.Length: 264 | self.GwAdd = None 265 | else: 266 | self.GwAdd = buffer[pos:] 267 | 268 | def __str__(self): 269 | buf = str(self.mh) + " Radius "+str(self.GwId) 270 | if self.GwAdd: 271 | buf += " GwAdd "+self.GwAdd 272 | return buf 273 | 274 | class Connects(Packets): 275 | 276 | def __init__(self, buffer = None): 277 | self.mh = MessageHeaders(CONNECT) 278 | self.Flags = Flags() 279 | self.ProtocolId = 1 280 | self.Duration = 30 281 | self.ClientId = "" 282 | if buffer != None: 283 | self.unpack(buffer) 284 | 285 | def pack(self): 286 | self.ClientId = str(self.ClientId).encode() 287 | fmt = '>%ds' % len(self.ClientId) 288 | buffer = self.Flags.pack() + struct.pack('>B', self.ProtocolId) + writeInt16(self.Duration) + struct.pack(fmt, self.ClientId) 289 | return self.mh.pack(len(buffer)) + buffer 290 | 291 | def unpack(self, buffer): 292 | pos = self.mh.unpack(buffer) 293 | assert self.mh.MsgType == CONNECT 294 | pos += self.Flags.unpack([buffer[pos]]) 295 | self.ProtocolId = buffer[pos] 296 | pos += 1 297 | self.Duration = readInt16(buffer[pos:]) 298 | pos += 2 299 | self.ClientId = buffer[pos:] 300 | 301 | def __str__(self): 302 | buf = str(self.mh) + ", " + str(self.Flags) + \ 303 | ", ProtocolId " + str(self.ProtocolId) + \ 304 | ", Duration " + str(self.Duration) + \ 305 | ", ClientId " + str(self.ClientId) 306 | return buf 307 | 308 | def __eq__(self, packet): 309 | rc = Packets.__eq__(self, packet) and \ 310 | self.Flags == packet.Flags and \ 311 | self.ProtocolId == packet.ProtocolId and \ 312 | self.Duration == packet.Duration and \ 313 | self.ClientId == packet.ClientId 314 | return rc 315 | 316 | 317 | class Connacks(Packets): 318 | 319 | def __init__(self, buffer = None): 320 | self.mh = MessageHeaders(CONNACK) 321 | self.ReturnCode = 0 # 1 byte 322 | if buffer != None: 323 | self.unpack(buffer) 324 | 325 | def pack(self): 326 | buffer = struct.pack('>B', self.ReturnCode) 327 | return self.mh.pack(len(buffer)) + buffer 328 | 329 | def unpack(self, buffer): 330 | pos = self.mh.unpack(buffer) 331 | assert self.mh.MsgType == CONNACK 332 | self.ReturnCode = buffer[pos] 333 | 334 | def __str__(self): 335 | return str(self.mh)+", ReturnCode "+str(self.ReturnCode) 336 | 337 | def __eq__(self, packet): 338 | return Packets.__eq__(self, packet) and \ 339 | self.ReturnCode == packet.ReturnCode 340 | 341 | 342 | class WillTopicReqs(Packets): 343 | 344 | def __init__(self, buffer = None): 345 | self.mh = MessageHeaders(WILLTOPICREQ) 346 | if buffer != None: 347 | self.unpack(buffer) 348 | 349 | def unpack(self, buffer): 350 | pos = self.mh.unpack(buffer) 351 | assert self.mh.MsgType == WILLTOPICREQ 352 | 353 | 354 | class WillTopics(Packets): 355 | 356 | def __init__(self, buffer = None): 357 | self.mh = MessageHeaders(WILLTOPIC) 358 | self.flags = Flags() 359 | self.WillTopic = "" 360 | if buffer != None: 361 | self.unpack(buffer) 362 | 363 | def pack(self): 364 | self.WillTopic = str(self.WillTopic).encode() 365 | fmt = '>%ds' % len(self.WillTopic) 366 | buffer = self.flags.pack() + struct.pack(fmt, self.WillTopic) 367 | return self.mh.pack(len(buffer)) + buffer 368 | 369 | def unpack(self, buffer): 370 | pos = self.mh.unpack(buffer) 371 | assert self.mh.MsgType == WILLTOPIC 372 | pos += self.flags.unpack(buffer[pos:]) 373 | self.WillTopic = buffer[pos:self.mh.Length] 374 | 375 | def __str__(self): 376 | return str(self.mh)+", Flags "+str(self.flags)+", WillTopic "+str(self.WillTopic) 377 | 378 | def __eq__(self, packet): 379 | return Packets.__eq__(self, packet) and \ 380 | self.flags == packet.flags and \ 381 | self.WillTopic == packet.WillTopic 382 | 383 | class WillMsgReqs(Packets): 384 | 385 | def __init__(self, buffer = None): 386 | self.mh = MessageHeaders(WILLMSGREQ) 387 | if buffer != None: 388 | self.unpack(buffer) 389 | 390 | def unpack(self, buffer): 391 | pos = self.mh.unpack(buffer) 392 | assert self.mh.MsgType == WILLMSGREQ 393 | 394 | 395 | class WillMsgs(Packets): 396 | 397 | def __init__(self, buffer = None): 398 | self.mh = MessageHeaders(WILLMSG) 399 | self.WillMsg = "" 400 | if buffer != None: 401 | self.unpack(buffer) 402 | 403 | def pack(self): 404 | self.WillMsg = str(self.WillMsg).encode() 405 | fmt = '>%ds' % len(self.WillMsg) 406 | return self.mh.pack(len(self.WillMsg)) + struct.pack(fmt, self.WillMsg) 407 | 408 | def unpack(self, buffer): 409 | pos = self.mh.unpack(buffer) 410 | assert self.mh.MsgType == WILLMSG 411 | self.WillMsg = buffer[pos:self.mh.Length] 412 | 413 | def __str__(self): 414 | return str(self.mh)+", WillMsg "+str(self.WillMsg) 415 | 416 | def __eq__(self, packet): 417 | return Packets.__eq__(self, packet) and \ 418 | self.WillMsg == packet.WillMsg 419 | 420 | class Registers(Packets): 421 | 422 | def __init__(self, buffer = None): 423 | self.mh = MessageHeaders(REGISTER) 424 | self.TopicId = 0 425 | self.MsgId = 0 426 | self.TopicName = "" 427 | if buffer != None: 428 | self.unpack(buffer) 429 | 430 | def pack(self): 431 | self.TopicName = str(self.TopicName).encode() 432 | fmt = '>%ds' % len(self.TopicName) 433 | buffer = writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack(fmt, self.TopicName) 434 | return self.mh.pack(len(buffer)) + buffer 435 | 436 | def unpack(self, buffer): 437 | pos = self.mh.unpack(buffer) 438 | assert self.mh.MsgType == REGISTER 439 | self.TopicId = readInt16(buffer[pos:]) 440 | pos += 2 441 | self.MsgId = readInt16(buffer[pos:]) 442 | pos += 2 443 | self.TopicName = buffer[pos:self.mh.Length] 444 | 445 | def __str__(self): 446 | return str(self.mh)+", TopicId "+str(self.TopicId)+", MsgId "+str(self.MsgId)+", TopicName "+str(self.TopicName) 447 | 448 | def __eq__(self, packet): 449 | return Packets.__eq__(self, packet) and \ 450 | self.TopicId == packet.TopicId and \ 451 | self.MsgId == packet.MsgId and \ 452 | self.TopicName == packet.TopicName 453 | 454 | 455 | class Regacks(Packets): 456 | 457 | def __init__(self, buffer = None): 458 | self.mh = MessageHeaders(REGACK) 459 | self.TopicId = 0 460 | self.MsgId = 0 461 | self.ReturnCode = 0 # 1 byte 462 | if buffer != None: 463 | self.unpack(buffer) 464 | 465 | def pack(self): 466 | buffer = writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack('>B', self.ReturnCode) 467 | return self.mh.pack(len(buffer)) + buffer 468 | 469 | def unpack(self, buffer): 470 | pos = self.mh.unpack(buffer) 471 | assert self.mh.MsgType == REGACK 472 | self.TopicId = readInt16(buffer[pos:]) 473 | pos += 2 474 | self.MsgId = readInt16(buffer[pos:]) 475 | pos += 2 476 | self.ReturnCode = buffer[pos] 477 | 478 | def __str__(self): 479 | return str(self.mh)+", TopicId "+str(self.TopicId)+", MsgId "+str(self.MsgId)+", ReturnCode "+str(self.ReturnCode) 480 | 481 | def __eq__(self, packet): 482 | return Packets.__eq__(self, packet) and \ 483 | self.TopicId == packet.TopicId and \ 484 | self.MsgId == packet.MsgId and \ 485 | self.ReturnCode == packet.ReturnCode 486 | 487 | 488 | class Publishes(Packets): 489 | 490 | def __init__(self, buffer = None): 491 | self.mh = MessageHeaders(PUBLISH) 492 | self.Flags = Flags() 493 | self.TopicId = 0 # 2 bytes 494 | self.TopicName = "" 495 | self.MsgId = 0 # 2 bytes 496 | self.Data = "" 497 | if buffer != None: 498 | self.unpack(buffer) 499 | 500 | def pack(self): 501 | buffer = self.Flags.pack() 502 | if self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_PREDEFINED, 3]: 503 | #print("topic id is", self.TopicId) 504 | buffer += writeInt16(self.TopicId) 505 | elif self.Flags.TopicIdType == TOPIC_SHORTNAME: 506 | topic_short = (self.TopicName + " ")[0:2] 507 | topic_short = topic_short.encode() 508 | fmt = '>%ds' % len(topic_short) 509 | buffer += topic_short 510 | if isinstance(self.Data, str): 511 | self.Data = str(self.Data).encode() 512 | fmt = '>%ds' % len(self.Data) 513 | self.Data = struct.pack(fmt, self.Data) 514 | elif isinstance(self.Data, bytes): 515 | pass 516 | buffer += writeInt16(self.MsgId) + self.Data 517 | return self.mh.pack(len(buffer)) + buffer 518 | 519 | def unpack(self, buffer): 520 | pos = self.mh.unpack(buffer) 521 | assert self.mh.MsgType == PUBLISH 522 | pos += self.Flags.unpack(buffer[pos:]) 523 | 524 | self.TopicId = 0 525 | self.TopicName = "" 526 | if self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_PREDEFINED]: 527 | self.TopicId = readInt16(buffer[pos:]) 528 | elif self.Flags.TopicIdType == TOPIC_SHORTNAME: 529 | self.TopicName = buffer[pos:pos+2] 530 | pos += 2 531 | self.MsgId = readInt16(buffer[pos:]) 532 | pos += 2 533 | self.Data = buffer[pos:self.mh.Length] 534 | 535 | def __str__(self): 536 | return str(self.mh)+", Flags "+str(self.Flags)+", TopicId "+str(self.TopicId)+", MsgId "+str(self.MsgId)+", Data "+str(self.Data) 537 | 538 | def __eq__(self, packet): 539 | return Packets.__eq__(self, packet) and \ 540 | self.Flags == packet.Flags and \ 541 | self.TopicId == packet.TopicId and \ 542 | self.MsgId == packet.MsgId and \ 543 | self.Data == packet.Data 544 | 545 | 546 | class Pubacks(Packets): 547 | 548 | def __init__(self, buffer = None): 549 | self.mh = MessageHeaders(PUBACK) 550 | self.TopicId = 0 551 | self.MsgId = 0 552 | self.ReturnCode = 0 # 1 byte 553 | if buffer != None: 554 | self.unpack(buffer) 555 | 556 | def pack(self): 557 | buffer = writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack('>B', self.ReturnCode) 558 | return self.mh.pack(len(buffer)) + buffer 559 | 560 | def unpack(self, buffer): 561 | pos = self.mh.unpack(buffer) 562 | assert self.mh.MsgType == PUBACK 563 | self.TopicId = readInt16(buffer[pos:]) 564 | pos += 2 565 | self.MsgId = readInt16(buffer[pos:]) 566 | pos += 2 567 | self.ReturnCode = buffer[pos] 568 | 569 | def __str__(self): 570 | return str(self.mh)+", TopicId "+str(self.TopicId)+" , MsgId "+str(self.MsgId)+", ReturnCode "+str(self.ReturnCode) 571 | 572 | def __eq__(self, packet): 573 | return Packets.__eq__(self, packet) and \ 574 | self.TopicId == packet.TopicId and \ 575 | self.MsgId == packet.MsgId and \ 576 | self.ReturnCode == packet.ReturnCode 577 | 578 | 579 | class Pubrecs(Packets): 580 | 581 | def __init__(self, buffer = None): 582 | self.mh = MessageHeaders(PUBREC) 583 | self.MsgId = 0 584 | if buffer != None: 585 | self.unpack(buffer) 586 | 587 | def pack(self): 588 | return self.mh.pack(2) + writeInt16(self.MsgId) 589 | 590 | def unpack(self, buffer): 591 | pos = self.mh.unpack(buffer) 592 | assert self.mh.MsgType == PUBREC 593 | self.MsgId = readInt16(buffer[pos:]) 594 | 595 | def __str__(self): 596 | return str(self.mh)+" , MsgId "+str(self.MsgId) 597 | 598 | def __eq__(self, packet): 599 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 600 | 601 | class Pubrels(Packets): 602 | 603 | def __init__(self, buffer = None): 604 | self.mh = MessageHeaders(PUBREL) 605 | self.MsgId = 0 606 | if buffer != None: 607 | self.unpack(buffer) 608 | 609 | def pack(self): 610 | return self.mh.pack(2) + writeInt16(self.MsgId) 611 | 612 | def unpack(self, buffer): 613 | pos = self.mh.unpack(buffer) 614 | assert self.mh.MsgType == PUBREL 615 | self.MsgId = readInt16(buffer[pos:]) 616 | 617 | def __str__(self): 618 | return str(self.mh)+" , MsgId "+str(self.MsgId) 619 | 620 | def __eq__(self, packet): 621 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 622 | 623 | 624 | class Pubcomps(Packets): 625 | 626 | def __init__(self, buffer = None): 627 | self.mh = MessageHeaders(PUBCOMP) 628 | self.MsgId = 0 629 | if buffer != None: 630 | self.unpack(buffer) 631 | 632 | def pack(self): 633 | return self.mh.pack(2) + writeInt16(self.MsgId) 634 | 635 | def unpack(self, buffer): 636 | pos = self.mh.unpack(buffer) 637 | assert self.mh.MsgType == PUBCOMP 638 | self.MsgId = readInt16(buffer[pos:]) 639 | 640 | def __str__(self): 641 | return str(self.mh)+" , MsgId "+str(self.MsgId) 642 | 643 | def __eq__(self, packet): 644 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 645 | 646 | 647 | class Subscribes(Packets): 648 | 649 | def __init__(self, buffer = None): 650 | self.mh = MessageHeaders(SUBSCRIBE) 651 | self.Flags = Flags() 652 | self.MsgId = 0 # 2 bytes 653 | self.TopicId = 0 # 2 bytes 654 | self.TopicName = "" 655 | if buffer != None: 656 | self.unpack(buffer) 657 | 658 | def pack(self): 659 | buffer = self.Flags.pack() + writeInt16(self.MsgId) 660 | if self.Flags.TopicIdType == TOPIC_PREDEFINED: 661 | buffer += writeInt16(self.TopicId) 662 | elif self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_SHORTNAME]: 663 | self.TopicName = str(self.TopicName).encode() 664 | fmt = '>%ds' % len(self.TopicName) 665 | buffer += struct.pack(fmt, self.TopicName) 666 | return self.mh.pack(len(buffer)) + buffer 667 | 668 | 669 | def unpack(self, buffer): 670 | pos = self.mh.unpack(buffer) 671 | assert self.mh.MsgType == SUBSCRIBE 672 | pos += self.Flags.unpack(buffer[pos:]) 673 | self.MsgId = readInt16(buffer[pos:]) 674 | pos += 2 675 | self.TopicId = 0 676 | self.TopicName = "" 677 | if self.Flags.TopicIdType == TOPIC_PREDEFINED: 678 | self.TopicId = readInt16(buffer[pos:]) 679 | elif self.Flags.TopicIdType in [TOPIC_NORMAL, TOPIC_SHORTNAME]: 680 | self.TopicName = buffer[pos:pos+2] 681 | 682 | def __str__(self): 683 | buffer = str(self.mh)+", Flags "+str(self.Flags)+", MsgId "+str(self.MsgId) 684 | if self.Flags.TopicIdType == 0: 685 | buffer += ", TopicName "+str(self.TopicName) 686 | elif self.Flags.TopicIdType == 1: 687 | buffer += ", TopicId "+str(self.TopicId) 688 | elif self.Flags.TopicIdType == 2: 689 | buffer += ", TopicId "+str(self.TopicId) 690 | return buffer 691 | 692 | def __eq__(self, packet): 693 | if self.Flags.TopicIdType == 0: 694 | if packet == None: 695 | rc = False 696 | else: 697 | rc = self.TopicName == packet.TopicName 698 | else: 699 | if packet == None: 700 | rc = False 701 | else: 702 | rc = self.TopicId == packet.TopicId 703 | return Packets.__eq__(self, packet) and \ 704 | self.Flags == packet.Flags and \ 705 | self.MsgId == packet.MsgId and rc 706 | 707 | 708 | class Subacks(Packets): 709 | 710 | def __init__(self, buffer = None): 711 | self.mh = MessageHeaders(SUBACK) 712 | self.Flags = Flags() # 1 byte 713 | self.TopicId = 0 # 2 bytes 714 | self.MsgId = 0 # 2 bytes 715 | self.ReturnCode = 0 # 1 byte 716 | if buffer != None: 717 | self.unpack(buffer) 718 | 719 | def pack(self): 720 | buffer = self.Flags.pack() + writeInt16(self.TopicId) + writeInt16(self.MsgId) + struct.pack('>B', self.ReturnCode) 721 | return self.mh.pack(len(buffer)) + buffer 722 | 723 | def unpack(self, buffer): 724 | pos = self.mh.unpack(buffer) 725 | assert self.mh.MsgType == SUBACK 726 | pos += self.Flags.unpack(buffer[pos:]) 727 | self.TopicId = readInt16(buffer[pos:]) 728 | pos += 2 729 | self.MsgId = readInt16(buffer[pos:]) 730 | pos += 2 731 | self.ReturnCode = buffer[pos] 732 | 733 | def __str__(self): 734 | return str(self.mh)+", Flags "+str(self.Flags)+", TopicId "+str(self.TopicId)+" , MsgId "+str(self.MsgId)+", ReturnCode "+str(self.ReturnCode) 735 | 736 | def __eq__(self, packet): 737 | return Packets.__eq__(self, packet) and \ 738 | self.Flags == packet.Flags and \ 739 | self.TopicId == packet.TopicId and \ 740 | self.MsgId == packet.MsgId and \ 741 | self.ReturnCode == packet.ReturnCode 742 | 743 | 744 | class Unsubscribes(Packets): 745 | 746 | def __init__(self, buffer = None): 747 | self.mh = MessageHeaders(UNSUBSCRIBE) 748 | self.Flags = Flags() 749 | self.MsgId = 0 # 2 bytes 750 | self.TopicId = 0 # 2 bytes 751 | self.TopicName = "" 752 | if buffer != None: 753 | self.unpack(buffer) 754 | 755 | def pack(self): 756 | buffer = self.Flags.pack() + writeInt16(self.MsgId) 757 | if self.Flags.TopicIdType == 0: 758 | self.TopicName = str(self.TopicName).encode() 759 | fmt = '>%ds' % len(self.TopicName) 760 | buffer += struct.pack(fmt, self.TopicName) 761 | elif self.Flags.TopicIdType == 1: 762 | buffer += writeInt16(self.TopicId) 763 | elif self.Flags.TopicIdType == 2: 764 | self.TopicId = str(self.TopicId).encode() 765 | fmt = '>%ds' % len(self.TopicId) 766 | buffer += struct.pack(fmt, self.TopicId) 767 | return self.mh.pack(len(buffer)) + buffer 768 | 769 | def unpack(self, buffer): 770 | pos = self.mh.unpack(buffer) 771 | assert self.mh.MsgType == UNSUBSCRIBE 772 | pos += self.Flags.unpack(buffer[pos:]) 773 | self.MsgId = readInt16(buffer[pos:]) 774 | pos += 2 775 | self.TopicId = 0 776 | self.TopicName = "" 777 | if self.Flags.TopicIdType == 0: 778 | self.TopicName = buffer[pos:self.mh.Length] 779 | elif self.Flags.TopicIdType == 1: 780 | self.TopicId = readInt16(buffer[pos:]) 781 | elif self.Flags.TopicIdType == 3: 782 | self.TopicId = buffer[pos:pos+2] 783 | 784 | def __str__(self): 785 | buffer = str(self.mh)+", Flags "+str(self.Flags)+", MsgId "+str(self.MsgId) 786 | if self.Flags.TopicIdType == 0: 787 | buffer += ", TopicName "+str(self.TopicName) 788 | elif self.Flags.TopicIdType == 1: 789 | buffer += ", TopicId "+str(self.TopicId) 790 | elif self.Flags.TopicIdType == 2: 791 | buffer += ", TopicId "+str(self.TopicId) 792 | return buffer 793 | 794 | def __eq__(self, packet): 795 | return Packets.__eq__(self, packet) and \ 796 | self.Flags == packet.Flags and \ 797 | self.MsgId == packet.MsgId and \ 798 | self.TopicId == packet.TopicId and \ 799 | self.TopicName == packet.TopicName 800 | 801 | class Unsubacks(Packets): 802 | 803 | def __init__(self, buffer = None): 804 | self.mh = MessageHeaders(UNSUBACK) 805 | self.MsgId = 0 806 | if buffer != None: 807 | self.unpack(buffer) 808 | 809 | def pack(self): 810 | return self.mh.pack(2) + writeInt16(self.MsgId) 811 | 812 | def unpack(self, buffer): 813 | pos = self.mh.unpack(buffer) 814 | assert self.mh.MsgType == UNSUBACK 815 | self.MsgId = readInt16(buffer[pos:]) 816 | 817 | def __str__(self): 818 | return str(self.mh)+" , MsgId "+str(self.MsgId) 819 | 820 | def __eq__(self, packet): 821 | return Packets.__eq__(self, packet) and self.MsgId == packet.MsgId 822 | 823 | 824 | class Pingreqs(Packets): 825 | 826 | def __init__(self, buffer = None): 827 | self.mh = MessageHeaders(PINGREQ) 828 | self.ClientId = None 829 | if buffer != None: 830 | self.unpack(buffer) 831 | 832 | def pack(self): 833 | if self.ClientId: 834 | self.ClientId = str(self.ClientId).encode() 835 | fmt = '>%ds' % len(self.ClientId) 836 | buf = self.mh.pack(len(self.ClientId)) + struct.pack(fmt, self.ClientId) 837 | else: 838 | buf = self.mh.pack(0) 839 | return buf 840 | 841 | def unpack(self, buffer): 842 | pos = self.mh.unpack(buffer) 843 | assert self.mh.MsgType == PINGREQ 844 | self.ClientId = buffer[pos:self.mh.Length] 845 | if self.ClientId == b'': 846 | self.ClientId = None 847 | 848 | def __str__(self): 849 | buf = str(self.mh) 850 | if self.ClientId: 851 | buf += ", ClientId "+str(self.ClientId) 852 | return buf 853 | 854 | def __eq__(self, packet): 855 | return Packets.__eq__(self, packet) and \ 856 | self.ClientId == packet.ClientId 857 | 858 | 859 | class Pingresps(Packets): 860 | 861 | def __init__(self, buffer = None): 862 | self.mh = MessageHeaders(PINGRESP) 863 | if buffer != None: 864 | self.unpack(buffer) 865 | 866 | def unpack(self, buffer): 867 | pos = self.mh.unpack(buffer) 868 | assert self.mh.MsgType == PINGRESP 869 | 870 | class Disconnects(Packets): 871 | 872 | def __init__(self, buffer = None): 873 | self.mh = MessageHeaders(DISCONNECT) 874 | self.Duration = None 875 | if buffer != None: 876 | self.unpack(buffer) 877 | 878 | def pack(self): 879 | if self.Duration: 880 | buf = self.mh.pack(2) + writeInt16(self.Duration) 881 | else: 882 | buf = self.mh.pack(0) 883 | return buf 884 | 885 | def unpack(self, buffer): 886 | pos = self.mh.unpack(buffer) 887 | assert self.mh.MsgType == DISCONNECT 888 | buf = buffer[pos:self.mh.Length] 889 | if buf == b'': 890 | self.Duration = None 891 | else: 892 | self.Duration = readInt16(buffer[pos:]) 893 | 894 | def __str__(self): 895 | buf = str(self.mh) 896 | if self.Duration: 897 | buf += ", Duration "+str(self.Duration) 898 | return buf 899 | 900 | def __eq__(self, packet): 901 | return Packets.__eq__(self, packet) and \ 902 | self.Duration == packet.Duration 903 | 904 | class WillTopicUpds(Packets): 905 | 906 | def __init__(self, buffer = None): 907 | self.mh = MessageHeaders(WILLTOPICUPD) 908 | self.flags = Flags() 909 | self.WillTopic = "" 910 | if buffer != None: 911 | self.unpack(buffer) 912 | 913 | def pack(self): 914 | self.WillTopic = str(self.WillTopic).encode() 915 | fmt = '>%ds' % len(self.WillTopic) 916 | buffer = self.flags.pack() + struct.pack(fmt, self.WillTopic) 917 | return self.mh.pack(len(buffer)) + buffer 918 | 919 | def unpack(self, buffer): 920 | pos = self.mh.unpack(buffer) 921 | assert self.mh.MsgType == WILLTOPICUPD 922 | pos += self.flags.unpack(buffer[pos:]) 923 | self.WillTopic = buffer[pos:self.mh.Length] 924 | 925 | def __str__(self): 926 | return str(self.mh)+", Flags "+str(self.flags)+", WillTopic "+str(self.WillTopic) 927 | 928 | def __eq__(self, packet): 929 | return Packets.__eq__(self, packet) and \ 930 | self.flags == packet.flags and \ 931 | self.WillTopic == packet.WillTopic 932 | 933 | class WillMsgUpds(Packets): 934 | 935 | def __init__(self, buffer = None): 936 | self.mh = MessageHeaders(WILLMSGUPD) 937 | self.WillMsg = "" 938 | if buffer != None: 939 | self.unpack(buffer) 940 | 941 | def pack(self): 942 | self.WillMsg = str(self.WillMsg).encode() 943 | fmt = '>%ds' % len(self.WillMsg) 944 | return self.mh.pack(len(self.WillMsg)) + struct.pack(fmt, self.WillMsg) 945 | 946 | def unpack(self, buffer): 947 | pos = self.mh.unpack(buffer) 948 | assert self.mh.MsgType == WILLMSGUPD 949 | self.WillMsg = buffer[pos:self.mh.Length] 950 | 951 | def __str__(self): 952 | return str(self.mh)+", WillMsg "+str(self.WillMsg) 953 | 954 | def __eq__(self, packet): 955 | return Packets.__eq__(self, packet) and \ 956 | self.WillMsg == packet.WillMsg 957 | 958 | class WillTopicResps(Packets): 959 | 960 | def __init__(self, buffer = None): 961 | self.mh = MessageHeaders(WILLTOPICRESP) 962 | self.ReturnCode = 0 963 | if buffer != None: 964 | self.unpack(buffer) 965 | 966 | def pack(self): 967 | buffer = writeInt16(self.ReturnCode) 968 | return self.mh.pack(len(buffer)) + buffer 969 | 970 | def unpack(self, buffer): 971 | pos = self.mh.unpack(buffer) 972 | assert self.mh.MsgType == WILLTOPICRESP 973 | self.ReturnCode = readInt16(buffer[pos:]) 974 | 975 | def __str__(self): 976 | return str(self.mh)+", ReturnCode "+str(self.ReturnCode) 977 | 978 | def __eq__(self, packet): 979 | return Packets.__eq__(self, packet) and \ 980 | self.ReturnCode == packet.ReturnCode 981 | 982 | class WillMsgResps(Packets): 983 | 984 | def __init__(self, buffer = None): 985 | self.mh = MessageHeaders(WILLMSGRESP) 986 | self.ReturnCode = 0 987 | if buffer != None: 988 | self.unpack(buffer) 989 | 990 | def pack(self): 991 | buffer = writeInt16(self.ReturnCode) 992 | return self.mh.pack(len(buffer)) + buffer 993 | 994 | def unpack(self, buffer): 995 | pos = self.mh.unpack(buffer) 996 | assert self.mh.MsgType == WILLMSGRESP 997 | self.returnCode = readInt16(buffer[pos:]) 998 | 999 | def __str__(self): 1000 | return str(self.mh)+", ReturnCode "+str(self.ReturnCode) 1001 | 1002 | def __eq__(self, packet): 1003 | return Packets.__eq__(self, packet) and \ 1004 | self.ReturnCode == packet.ReturnCode 1005 | 1006 | objects = [Advertises, SearchGWs, GWInfos, None, 1007 | Connects, Connacks, 1008 | WillTopicReqs, WillTopics, WillMsgReqs, WillMsgs, 1009 | Registers, Regacks, 1010 | Publishes, Pubacks, Pubcomps, Pubrecs, Pubrels, None, 1011 | Subscribes, Subacks, Unsubscribes, Unsubacks, 1012 | Pingreqs, Pingresps, Disconnects, None, 1013 | WillTopicUpds, WillTopicResps, WillMsgUpds, WillMsgResps] 1014 | 1015 | def unpackPacket(msg): 1016 | (buffer, address) = msg 1017 | if MessageType(buffer) != None: 1018 | packet = objects[MessageType(buffer)]() 1019 | packet.unpack(buffer) 1020 | else: 1021 | packet = None 1022 | return packet, address 1023 | 1024 | if __name__ == "__main__": 1025 | print("Object string representations") 1026 | for o in objects: 1027 | if o: 1028 | print(o()) 1029 | 1030 | print("\nComparisons") 1031 | for o in [Flags] + objects: 1032 | if o: 1033 | o1 = o() 1034 | o2 = o() 1035 | o2.unpack(o1.pack()) 1036 | if o1 != o2: 1037 | print("error! ", str(o1.mh) if hasattr(o1, "mh") else o1.__class__.__name__) 1038 | print(str(o1)) 1039 | print(str(o2)) 1040 | else: 1041 | print("ok ", str(o1.mh) if hasattr(o1, "mh") else o1.__class__.__name__) 1042 | -------------------------------------------------------------------------------- /umqttsn/MQTTSNclient.py: -------------------------------------------------------------------------------- 1 | """ 2 | /******************************************************************************* 3 | * Copyright (c) 2011, 2013 IBM Corp. 4 | * 5 | * All rights reserved. This program and the accompanying materials 6 | * are made available under the terms of the Eclipse Public License v1.0 7 | * and Eclipse Distribution License v1.0 which accompany this distribution. 8 | * 9 | * The Eclipse Public License is available at 10 | * http://www.eclipse.org/legal/epl-v10.html 11 | * and the Eclipse Distribution License is available at 12 | * http://www.eclipse.org/org/documents/edl-v10.php. 13 | * 14 | * Contributors: 15 | * Ian Craggs - initial API and implementation and/or initial documentation 16 | * EH Ong - port to Python 3 and Micropython 17 | *******************************************************************************/ 18 | """ 19 | 20 | import MQTTSN 21 | import MQTTSNinternal 22 | import socket, time, _thread, sys, struct, queue 23 | 24 | 25 | class Callback: 26 | 27 | def __init__(self): 28 | self.events = [] 29 | 30 | def connectionLost(self, cause): 31 | print("default connectionLost", cause) 32 | self.events.append("disconnected") 33 | 34 | def messageArrived(self, topicName, payload, qos, retained, msgid): 35 | print("default publishArrived", topicName, payload, qos, retained, msgid) 36 | return True 37 | 38 | def deliveryComplete(self, msgid): 39 | print("default deliveryComplete") 40 | 41 | def advertise(self, address, gwid, duration): 42 | print("advertise", address, gwid, duration) 43 | 44 | class TopicMap: 45 | 46 | def __init__(self): 47 | self.registered = {} 48 | 49 | def register(self, topicId, topicName): 50 | self.registered[topicId] = topicName 51 | 52 | class Client: 53 | 54 | def __init__(self, clientid, host="localhost", port=1883): 55 | self.clientid = clientid 56 | self.host = host 57 | self.port = port 58 | self.msgid = 1 59 | self.callback = None 60 | self.__receiver = None 61 | self.topicmap = TopicMap() 62 | self.queue = queue.Queue() 63 | 64 | def start(self): 65 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP) 66 | self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 67 | self.sock.bind((self.host, self.port)) 68 | mreq = struct.pack("4sl", socket.inet_aton(self.host), socket.INADDR_ANY) 69 | 70 | self.sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq) 71 | 72 | self.startReceiver() 73 | 74 | def stop(self): 75 | self.stopReceiver() 76 | 77 | def __nextMsgid(self): 78 | def getWrappedMsgid(): 79 | id = self.msgid + 1 80 | if id == 65535: 81 | id = 1 82 | return id 83 | 84 | if len(self.__receiver.outMsgs) >= 65535: 85 | raise "No slots left!!" 86 | else: 87 | self.msgid = getWrappedMsgid() 88 | while self.msgid in self.__receiver.outMsgs: 89 | self.msgid = getWrappedMsgid() 90 | return self.msgid 91 | 92 | 93 | def registerCallback(self, callback): 94 | self.callback = callback 95 | 96 | 97 | def connect(self, cleansession=True): 98 | self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 99 | self.sock.settimeout(5.0) 100 | 101 | self.sock.connect((self.host, self.port)) 102 | 103 | connect = MQTTSN.Connects() 104 | connect.ClientId = self.clientid 105 | connect.CleanSession = cleansession 106 | connect.KeepAliveTimer = 0 107 | self.sock.send(connect.pack()) 108 | 109 | response, address = MQTTSN.unpackPacket(MQTTSN.getPacket(self.sock)) 110 | assert response.mh.MsgType == MQTTSN.CONNACK 111 | 112 | self.startReceiver() 113 | 114 | 115 | def startReceiver(self): 116 | self.__receiver = MQTTSNinternal.Receivers(self.sock) 117 | if self.callback: 118 | id = _thread.start_new_thread(self.__receiver, (self.callback,self.topicmap,self.queue,)) 119 | 120 | 121 | def waitfor(self, msgType, msgId=None): 122 | if self.__receiver: 123 | msg = self.__receiver.waitfor(msgType, msgId) 124 | else: 125 | msg = self.__receiver.receive() 126 | while msg.mh.MsgType != msgType and (msgId == None or msgId == msg.MsgId): 127 | msg = self.__receiver.receive() 128 | return msg 129 | 130 | 131 | def subscribe(self, topic, qos=0): 132 | subscribe = MQTTSN.Subscribes() 133 | subscribe.MsgId = self.__nextMsgid() 134 | if isinstance(topic, str): 135 | subscribe.TopicName = topic 136 | if len(topic) > 2: 137 | subscribe.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 138 | else: 139 | subscribe.Flags.TopicIdType = MQTTSN.TOPIC_SHORTNAME 140 | else: 141 | subscribe.TopicId = topic # should be int 142 | subscribe.Flags.TopicIdType = MQTTSN.TOPIC_PREDEFINED 143 | subscribe.Flags.QoS = qos 144 | if self.__receiver: 145 | self.__receiver.lookfor(MQTTSN.SUBACK) 146 | self.sock.send(subscribe.pack()) 147 | msg = self.waitfor(MQTTSN.SUBACK, subscribe.MsgId) 148 | self.topicmap.register(msg.TopicId, topic) 149 | return msg.ReturnCode, msg.TopicId 150 | 151 | 152 | def unsubscribe(self, topics): 153 | unsubscribe = MQTTSN.Unsubscribes() 154 | unsubscribe.MsgId = self.__nextMsgid() 155 | unsubscribe.data = topics 156 | if self.__receiver: 157 | self.__receiver.lookfor(MQTTSN.UNSUBACK) 158 | self.sock.send(unsubscribe.pack()) 159 | msg = self.waitfor(MQTTSN.UNSUBACK, unsubscribe.MsgId) 160 | 161 | 162 | def register(self, topicName): 163 | register = MQTTSN.Registers() 164 | register.TopicName = topicName 165 | if self.__receiver: 166 | self.__receiver.lookfor(MQTTSN.REGACK) 167 | self.sock.send(register.pack()) 168 | msg = self.waitfor(MQTTSN.REGACK, register.MsgId) 169 | self.topicmap.register(msg.TopicId, topicName) 170 | return msg.TopicId 171 | 172 | 173 | def publish(self, topic, payload, qos=0, retained=False): 174 | if isinstance(payload, str) or isinstance(payload, bytes): 175 | pass 176 | else: 177 | raise TypeError('Payload must be str or bytes.') 178 | publish = MQTTSN.Publishes() 179 | publish.Flags.QoS = qos 180 | publish.Flags.Retain = retained 181 | if isinstance(topic, str): 182 | publish.Flags.TopicIdType = MQTTSN.TOPIC_SHORTNAME 183 | publish.TopicName = topic 184 | else: 185 | publish.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 186 | publish.TopicId = topic 187 | if qos in [-1, 0]: 188 | publish.MsgId = 0 189 | else: 190 | publish.MsgId = self.__nextMsgid() 191 | #print("MsgId", publish.MsgId) 192 | self.__receiver.outMsgs[publish.MsgId] = publish 193 | publish.Data = payload 194 | self.sock.send(publish.pack()) 195 | return publish.MsgId 196 | 197 | 198 | def disconnect(self): 199 | disconnect = MQTTSN.Disconnects() 200 | if self.__receiver: 201 | self.__receiver.lookfor(MQTTSN.DISCONNECT) 202 | self.sock.send(disconnect.pack()) 203 | msg = self.waitfor(MQTTSN.DISCONNECT) 204 | self.stopReceiver() 205 | 206 | 207 | def stopReceiver(self): 208 | self.sock.close() # this will stop the receiver too 209 | ## assert self.__receiver.inMsgs == {} 210 | ## assert self.__receiver.outMsgs == {} 211 | self.__receiver = None 212 | 213 | def receive(self): 214 | return self.__receiver.receive() 215 | 216 | 217 | def publish(topic, payload, retained=False, port=1883, host="localhost"): 218 | publish = MQTTSN.Publishes() 219 | publish.Flags.QoS = 3 220 | publish.Flags.Retain = retained 221 | if isinstance(payload, str): 222 | pass 223 | elif isinstance(payload, bytes): 224 | payload = payload.decode() 225 | if isinstance(topic, str): 226 | if len(topic) > 2: 227 | publish.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 228 | publish.TopicId = len(topic) 229 | payload = topic + payload 230 | else: 231 | publish.Flags.TopicIdType = MQTTSN.TOPIC_SHORTNAME 232 | publish.TopicName = topic 233 | else: 234 | publish.Flags.TopicIdType = MQTTSN.TOPIC_NORMAL 235 | publish.TopicId = topic 236 | publish.MsgId = 0 237 | #print("payload", payload) 238 | publish.Data = payload 239 | sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) 240 | sock.sendto(publish.pack(), (host, port)) 241 | sock.close() 242 | return 243 | 244 | 245 | if __name__ == "__main__": 246 | 247 | """ 248 | mclient = Client("myclientid", host="225.0.18.83", port=1883) 249 | mclient.registerCallback(Callback()) 250 | mclient.start() 251 | 252 | publish("long topic name", "qos -1 start", port=1884) 253 | 254 | callback = Callback() 255 | 256 | aclient = Client("myclientid", port=1884) 257 | aclient.registerCallback(callback) 258 | 259 | aclient.connect() 260 | aclient.disconnect() 261 | 262 | aclient.connect() 263 | aclient.subscribe("k ", 2) 264 | aclient.subscribe("jkjkjkjkj", 2) 265 | aclient.publish("k ", "qos 0") 266 | aclient.publish("k ", "qos 1", 1) 267 | aclient.publish("jkjkjkjkj", "qos 2", 2) 268 | topicid = aclient.register("jkjkjkjkj") 269 | #time.sleep(1.0) 270 | aclient.publish(topicid, "qos 2 - registered topic id", 2) 271 | #time.sleep(1.0) 272 | aclient.disconnect() 273 | publish("long topic name", "qos -1 end", port=1884) 274 | 275 | time.sleep(30) 276 | mclient.stop() 277 | """ 278 | 279 | 280 | aclient = Client("linh", port=1885) 281 | aclient.registerCallback(Callback()) 282 | aclient.connect() 283 | 284 | rc, topic1 = aclient.subscribe("topic1") 285 | print("topic id for topic1 is", topic1) 286 | rc, topic2 = aclient.subscribe("topic2") 287 | print("topic id for topic2 is", topic2) 288 | aclient.publish(topic1, "aaaa", qos=0) 289 | aclient.publish(topic2, "bbbb", qos=0) 290 | aclient.unsubscribe("topic1") 291 | aclient.publish(topic2, "bbbb", qos=0) 292 | aclient.publish(topic1, "aaaa", qos=0) 293 | aclient.disconnect() 294 | 295 | 296 | 297 | -------------------------------------------------------------------------------- /umqttsn/MQTTSNinternal.py: -------------------------------------------------------------------------------- 1 | """ 2 | /******************************************************************************* 3 | * Copyright (c) 2011, 2013 IBM Corp. 4 | * 5 | * All rights reserved. This program and the accompanying materials 6 | * are made available under the terms of the Eclipse Public License v1.0 7 | * and Eclipse Distribution License v1.0 which accompany this distribution. 8 | * 9 | * The Eclipse Public License is available at 10 | * http://www.eclipse.org/legal/epl-v10.html 11 | * and the Eclipse Distribution License is available at 12 | * http://www.eclipse.org/org/documents/edl-v10.php. 13 | * 14 | * Contributors: 15 | * Ian Craggs - initial API and implementation and/or initial documentation 16 | * EH Ong - port to Python 3 and Micropython 17 | *******************************************************************************/ 18 | """ 19 | 20 | import MQTTSN 21 | import time, sys, socket 22 | 23 | debug = False 24 | 25 | class Receivers: 26 | 27 | def __init__(self, socket): 28 | #print("initializing receiver") 29 | self.socket = socket 30 | self.connected = False 31 | self.observe = None 32 | self.observed = [] 33 | 34 | self.inMsgs = {} 35 | self.outMsgs = {} 36 | 37 | self.puback = MQTTSN.Pubacks() 38 | self.pubrec = MQTTSN.Pubrecs() 39 | self.pubrel = MQTTSN.Pubrels() 40 | self.pubcomp = MQTTSN.Pubcomps() 41 | 42 | def lookfor(self, msgType): 43 | self.observe = msgType 44 | 45 | def waitfor(self, msgType, msgId=None): 46 | msg = None 47 | count = 0 48 | while True: 49 | while len(self.observed) > 0: 50 | msg = self.observed.pop(0) 51 | if msg.mh.MsgType == msgType and (msgId == None or msg.MsgId == msgId): 52 | break 53 | else: 54 | msg = None 55 | if msg != None: 56 | break 57 | time.sleep(0.2) 58 | count += 1 59 | if count == 25: 60 | msg = None 61 | break 62 | self.observe = None 63 | return msg 64 | 65 | def receive(self, topicmap, callback=None): 66 | packet = None 67 | try: 68 | packet, address = MQTTSN.unpackPacket(MQTTSN.getPacket(self.socket)) 69 | except: 70 | if sys.exc_info()[0] != socket.timeout: 71 | #print("unexpected exception", sys.exc_info()) 72 | raise sys.exc_info() 73 | if packet == None: 74 | time.sleep(0.1) 75 | return 76 | elif debug: 77 | print(packet) 78 | 79 | if self.observe == packet.mh.MsgType: 80 | #print("observed", packet) 81 | self.observed.append(packet) 82 | 83 | elif packet.mh.MsgType == MQTTSN.ADVERTISE: 84 | if hasattr(callback, "advertise"): 85 | callback.advertise(address, packet.GwId, packet.Duration) 86 | 87 | elif packet.mh.MsgType == MQTTSN.REGISTER: 88 | topicmap.register(packet.TopicId, packet.TopicName) 89 | 90 | elif packet.mh.MsgType == MQTTSN.PUBACK: 91 | "check if we are expecting a puback" 92 | if packet.MsgId in self.outMsgs and \ 93 | self.outMsgs[packet.MsgId].Flags.QoS == 1: 94 | del self.outMsgs[packet.MsgId] 95 | if hasattr(callback, "published"): 96 | callback.published(packet.MsgId) 97 | else: 98 | raise Exception("No QoS 1 message with message id "+str(packet.MsgId)+" sent") 99 | 100 | elif packet.mh.MsgType == MQTTSN.PUBREC: 101 | if packet.MsgId in self.outMsgs: 102 | self.pubrel.MsgId = packet.MsgId 103 | self.socket.send(self.pubrel.pack()) 104 | else: 105 | raise Exception("PUBREC received for unknown msg id "+ \ 106 | str(packet.MsgId)) 107 | 108 | elif packet.mh.MsgType == MQTTSN.PUBREL: 109 | "release QOS 2 publication to client, & send PUBCOMP" 110 | msgid = packet.MsgId 111 | if packet.MsgId not in self.inMsgs: 112 | pass # what should we do here? 113 | else: 114 | pub = self.inMsgs[packet.MsgId] 115 | topicname = topicmap.registered[pub.TopicId] 116 | if callback == None or \ 117 | callback.messageArrived(topicname, pub.Data, 2, pub.Flags.Retain, pub.MsgId): 118 | del self.inMsgs[packet.MsgId] 119 | self.pubcomp.MsgId = packet.MsgId 120 | self.socket.send(self.pubcomp.pack()) 121 | if callback == None: 122 | return (topicname, pub.Data, 2, pub.Flags.Retain, pub.MsgId) 123 | 124 | elif packet.mh.MsgType == MQTTSN.PUBCOMP: 125 | "finished with this message id" 126 | if packet.MsgId in self.outMsgs: 127 | del self.outMsgs[packet.MsgId] 128 | if hasattr(callback, "published"): 129 | callback.published(packet.MsgId) 130 | else: 131 | raise Exception("PUBCOMP received for unknown msg id "+ \ 132 | str(packet.MsgId)) 133 | 134 | elif packet.mh.MsgType == MQTTSN.PUBLISH: 135 | "finished with this message id" 136 | if packet.Flags.QoS in [0, 3]: 137 | qos = packet.Flags.QoS 138 | topicname = topicmap.registered[packet.TopicId] 139 | data = packet.Data 140 | if qos == 3: 141 | qos = -1 142 | if packet.Flags.TopicIdType == MQTTSN.TOPICID: 143 | topicname = packet.Data[:packet.TopicId] 144 | data = packet.Data[packet.TopicId:] 145 | if callback == None: 146 | return (topicname, data, qos, packet.Flags.Retain, packet.MsgId) 147 | else: 148 | callback.messageArrived(topicname, data, qos, packet.Flags.Retain, packet.MsgId) 149 | elif packet.Flags.QoS == 1: 150 | topicname = topicmap.registered[packet.TopicId] 151 | if callback == None: 152 | return (topicname, packet.Data, 1, 153 | packet.Flags.Retain, packet.MsgId) 154 | else: 155 | if callback.messageArrived(topicname, packet.Data, 1, 156 | packet.Flags.Retain, packet.MsgId): 157 | self.puback.MsgId = packet.MsgId 158 | self.socket.send(self.puback.pack()) 159 | elif packet.Flags.QoS == 2: 160 | self.inMsgs[packet.MsgId] = packet 161 | self.pubrec.MsgId = packet.MsgId 162 | self.socket.send(self.pubrec.pack()) 163 | 164 | else: 165 | raise Exception("Unexpected packet"+str(packet)) 166 | return packet 167 | 168 | def __call__(self, callback, topicmap, queue): 169 | try: 170 | while True: 171 | self.receive(topicmap, callback) 172 | except: 173 | queue.put(sys.exc_info()) 174 | if sys.exc_info()[0] != socket.error: 175 | #print("unexpected exception", sys.exc_info()) 176 | pass 177 | --------------------------------------------------------------------------------