Package pymata_aio :: Module pymata_iot
[hide private]
[frames] | no frames]

Source Code for Module pymata_aio.pymata_iot

  1  #!/usr/bin/env python3 
  2   
  3  """ 
  4  Copyright (c) 2015 Alan Yorinks All rights reserved. 
  5   
  6  This program is free software; you can redistribute it and/or 
  7  modify it under the terms of the GNU  General Public 
  8  License as published by the Free Software Foundation; either 
  9  version 3 of the License, or (at your option) any later version. 
 10   
 11  This library is distributed in the hope that it will be useful, 
 12  but WITHOUT ANY WARRANTY; without even the implied warranty of 
 13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
 14  General Public License for more details. 
 15   
 16  You should have received a copy of the GNU General Public 
 17  License along with this library; if not, write to the Free Software 
 18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA 
 19  """ 
 20   
 21  import json 
 22  import asyncio 
 23  import datetime 
 24  import argparse 
 25   
 26  from autobahn.asyncio.websocket import WebSocketServerProtocol, \ 
 27      WebSocketServerFactory 
 28   
 29  from pymata_aio.pymata_core import PymataCore 
 30  from pymata_aio.constants import Constants 
31 32 33 -class PymataIOT(WebSocketServerProtocol):
34 """ 35 This class implements the PyMata Websocket interface. JSON command messages are received via Websocket connection, 36 decoded and mapped to an associated PyMata method to be executed 37 operation. 38 39 The methods below are not intended to be called directly. The JSON message format is documented as part of the 40 method description. All JSON reply messages (to be handled by the client) will also be documented for 41 within the description. 42 43 usage: pymata_iot.py [-h] [-host HOSTNAME] [-port PORT] [-wait WAIT] 44 [-comport COM] [-sleep SLEEP] 45 46 optional arguments: 47 -h, --help show this help message and exit 48 -host HOSTNAME Server name or IP address 49 -port PORT Server port number 50 -wait WAIT Arduino wait time 51 -comport COM Arduino COM port 52 -sleep SLEEP sleep tune in ms. 53 """ 54 parser = argparse.ArgumentParser() 55 parser.add_argument("-host", dest="hostname", default="localhost", help="Server name or IP address") 56 parser.add_argument("-port", dest="port", default="9000", help="Server port number") 57 parser.add_argument("-wait", dest="wait", default="2", help="Arduino wait time") 58 parser.add_argument("-comport", dest="com", default="None", help="Arduino COM port") 59 parser.add_argument("-sleep", dest="sleep", default=".001", help="sleep tune in ms.") 60 args = parser.parse_args() 61 62 ip_addr = args.hostname 63 ip_port = args.port 64 65 if args.com == 'None': 66 comport = None 67 else: 68 comport = args.com 69 70 core = PymataCore(int(args.wait), float(args.sleep), comport) 71 core.start() 72
73 - def __init__(self):
74 """ 75 This is the "constructor" for PymataIOT. It sets up a translation dictionary using incoming JSON commands 76 and maps them to command methods. 77 @return: No Return. 78 """ 79 80 self.command_map = { 81 "analog_read": self.analog_read, 82 "analog_write": self.analog_write, 83 "digital_read": self.digital_read, 84 "digital_write": self.digital_write, 85 "disable_analog_reporting": self.disable_analog_reporting, 86 "disable_digital_reporting": self.disable_digital_reporting, 87 "enable_analog_reporting": self.disable_analog_reporting, 88 "enable_digital_reporting": self.disable_digital_reporting, 89 "encoder_config": self.encoder_config, 90 "encoder_read": self.encoder_read, 91 "get_analog_latch_data": self.get_analog_latch_data, 92 "get_analog_map": self.get_analog_map, 93 "get_capability_report": self.get_capability_report, 94 "get_digital_latch_data": self.get_digital_latch_data, 95 "get_firmware_version": self.get_firmware_version, 96 "get_pin_state": self.get_pinstate_report, 97 "get_protocol_version": self.get_protocol_version, 98 "get_pymata_version": self.get_pymata_version, 99 "i2c_config": self.i2c_config, 100 "i2c_read_data": self.i2c_read_data, 101 "i2c_read_request": self.i2c_read_request, 102 "i2c_write_request": self.i2c_write_request, 103 "play_tone": self.play_tone, 104 "set_analog_latch": self.set_analog_latch, 105 "set_digital_latch": self.set_digital_latch, 106 "set_pin_mode": self.set_pin_mode, 107 "set_sampling_interval": self.set_sampling_interval, 108 "sonar_config": self.sonar_config, 109 "sonar_read": self.sonar_read, 110 "servo_config": self.servo_config, 111 "stepper_config": self.stepper_config, 112 "stepper_step": self.stepper_step 113 }
114 115 @asyncio.coroutine
116 - def analog_read(self, command):
117 """ 118 This method reads and returns the last reported value for an analog pin. 119 Normally not used since analog pin updates will be provided automatically 120 as they occur with the analog_message_reply being sent to the client after set_pin_mode is called. 121 (see enable_analog_reporting for message format). 122 123 @param command: {"method": "analog_read", "params": [ANALOG_PIN]} 124 @return: {"method": "analog_read_reply", "params": [PIN, ANALOG_DATA_VALUE]} 125 """ 126 pin = int(command[0]) 127 data_val = yield from self.core.analog_read(pin) 128 reply = json.dumps({"method": "analog_read_reply", "params": [pin, data_val]}) 129 self.sendMessage(reply.encode('utf8'))
130 131 @asyncio.coroutine
132 - def analog_write(self, command):
133 """ 134 This method writes a value to an analog pin. 135 136 It is used to set the output of a PWM pin or the angle of a Servo. 137 @param command: {"method": "analog_write", "params": [PIN, WRITE_VALUE]} 138 @return: No return message. 139 """ 140 pin = int(command[0]) 141 value = int(command[1]) 142 yield from self.core.analog_write(pin, value)
143 144 @asyncio.coroutine
145 - def digital_read(self, command):
146 """ 147 This method reads and returns the last reported value for a digital pin. 148 Normally not used since digital pin updates will be provided automatically 149 as they occur with the digital_message_reply being sent to the client after set_pin_mode is called.. 150 (see enable_digital_reporting for message format) 151 152 @param command: {"method": "digital_read", "params": [PIN]} 153 @return: {"method": "digital_read_reply", "params": [PIN, DIGITAL_DATA_VALUE]} 154 """ 155 pin = int(command[0]) 156 data_val = yield from self.core.digital_read(pin) 157 reply = json.dumps({"method": "digital_read_reply", "params": [pin, data_val]}) 158 self.sendMessage(reply.encode('utf8'))
159 160 @asyncio.coroutine
161 - def digital_write(self, command):
162 """ 163 This method writes a zero or one to a digital pin. 164 @param command: {"method": "digital_write", "params": [PIN, DIGITAL_DATA_VALUE]} 165 @return: No return message.. 166 """ 167 pin = int(command[0]) 168 value = int(command[1]) 169 yield from self.core.digital_write(pin, value)
170 171 @asyncio.coroutine
172 - def disable_analog_reporting(self, command):
173 """ 174 Disable Firmata reporting for an analog pin. 175 @param command: {"method": "disable_analog_reporting", "params": [PIN]} 176 @return: No return message.. 177 """ 178 pin = int(command[0]) 179 yield from self.core.disable_analog_reporting(pin)
180 181 @asyncio.coroutine
182 - def disable_digital_reporting(self, command):
183 """ 184 Disable Firmata reporting for a digital pin. 185 @param command: {"method": "disable_digital_reporting", "params": [PIN]} 186 @return: No return message. 187 """ 188 pin = int(command[0]) 189 yield from self.core.disable_digital_reporting(pin)
190 191 @asyncio.coroutine
192 - def enable_analog_reporting(self, command):
193 """ 194 Enable Firmata reporting for an analog pin. 195 @param command: {"method": "enable_analog_reporting", "params": [PIN]} 196 @return: {"method": "analog_message_reply", "params": [PIN, ANALOG_DATA_VALUE]} 197 """ 198 pin = int(command[0]) 199 yield from self.core.enable_analog_reporting(pin)
200 201 @asyncio.coroutine
202 - def enable_digital_reporting(self, command):
203 """ 204 Enable Firmata reporting for a digital pin. 205 206 @param command: {"method": "enable_digital_reporting", "params": [PIN]} 207 @return: {"method": "digital_message_reply", "params": [PIN, DIGITAL_DATA_VALUE]} 208 """ 209 pin = int(command[0]) 210 yield from self.core.enable_digital_reporting(pin)
211 212 @asyncio.coroutine
213 - def encoder_config(self, command):
214 """ 215 Configure 2 pins for FirmataPlus encoder operation. 216 217 @param command: {"method": "encoder_config", "params": [PIN_A, PIN_B]} 218 @return: {"method": "encoder_data_reply", "params": [ENCODER_DATA]} 219 """ 220 pin_a = int(command[0]) 221 pin_b = int(command[1]) 222 yield from self.core.encoder_config(pin_a, pin_b, self.encoder_callback)
223 224 @asyncio.coroutine
225 - def encoder_read(self, command):
226 """ 227 This is a polling method to read the last cached FirmataPlus encoder value. 228 Normally not used. See encoder config for the asynchronous report message format. 229 230 @param command: {"method": "encoder_read", "params": [PIN_A]} 231 @return: {"method": "encoder_read_reply", "params": [PIN_A, ENCODER_VALUE]} 232 """ 233 pin = int(command[0]) 234 val = yield from self.core.encoder_read(pin) 235 reply = json.dumps({"method": "encoder_read_reply", "params": [pin, val]}) 236 self.sendMessage(reply.encode('utf8'))
237 238 @asyncio.coroutine
239 - def get_analog_latch_data(self, command):
240 """ 241 This method retrieves a latch table entry for an analog pin. 242 243 See constants.py for definition of reply message parameters. 244 245 @param command: {"method": "get_analog_latch_data", "params": [ANALOG_PIN]} 246 @return: {"method": "get_analog_latch_data_reply", "params": [ANALOG_PIN, LATCHED_STATE, THRESHOLD_TYPE,\ 247 THRESHOLD_TARGET, DATA_VALUE, TIME_STAMP ]} 248 """ 249 pin = int(command[0]) 250 data_val = yield from self.core.get_analog_latch_data(pin) 251 if data_val: 252 data_val = data_val[0:-1] 253 reply = json.dumps({"method": "get_analog_latch_data_reply", "params": [pin, data_val]}) 254 self.sendMessage(reply.encode('utf8'))
255 256 @asyncio.coroutine
257 - def get_analog_map(self):
258 """ 259 This method retrieves the Firmata analog map. 260 261 Refer to: http://firmata.org/wiki/Protocol#Analog_Mapping_Query to interpret the reply 262 263 The command JSON format is: {"method":"get_analog_map","params":["null"]} 264 @return: {"method": "analog_map_reply", "params": [ANALOG_MAP]} 265 """ 266 value = yield from self.core.get_analog_map() 267 if value: 268 reply = json.dumps({"method": "analog_map_reply", "params": value}) 269 else: 270 reply = json.dumps({"method": "analog_map_reply", "params": "None"}) 271 self.sendMessage(reply.encode('utf8'))
272 273 @asyncio.coroutine
274 - def get_capability_report(self):
275 """ 276 This method retrieves the Firmata capability report. 277 278 Refer to http://firmata.org/wiki/Protocol#Capability_Query 279 280 The command format is: {"method":"get_capability_report","params":["null"]} 281 282 @return: {"method": "capability_report_reply", "params": [RAW_CAPABILITY_REPORT]} 283 """ 284 value = yield from self.core.get_capability_report() 285 asyncio.sleep(.1) 286 if value: 287 reply = json.dumps({"method": "capability_report_reply", "params": value}) 288 else: 289 reply = json.dumps({"method": "capability_report_reply", "params": "None"}) 290 self.sendMessage(reply.encode('utf8'))
291 292 @asyncio.coroutine
293 - def get_digital_latch_data(self, command):
294 """ 295 This method retrieves a latch table entry for a digital pin. 296 297 See constants.py for definition of reply message parameters. 298 299 @param command: {"method": "get_digital_latch_data", "params": [ANALOG_PIN]} 300 @return: {"method": "get_digital_latch_data_reply", "params": [DIGITAL_PIN, LATCHED_STATE, THRESHOLD_TYPE,\ 301 THRESHOLD_TARGET, DATA_VALUE, TIME_STAMP ]} 302 """ 303 pin = int(command[0]) 304 data_val = yield from self.core.get_digital_latch_data(pin) 305 if data_val: 306 data_val = data_val[0:-1] 307 reply = json.dumps({"method": "get_digital_latch_data_reply", "params": [pin, data_val]}) 308 self.sendMessage(reply.encode('utf8'))
309 310 @asyncio.coroutine
311 - def get_firmware_version(self):
312 """ 313 This method retrieves the Firmata firmware version. 314 315 See: http://firmata.org/wiki/Protocol#Query_Firmware_Name_and_Version 316 317 318 JSON command: {"method": "get_firmware_version", "params": ["null"]} 319 320 @return: {"method": "firmware_version_reply", "params": [FIRMWARE_VERSION]} 321 """ 322 value = yield from self.core.get_firmware_version() 323 if value: 324 reply = json.dumps({"method": "firmware_version_reply", "params": value}) 325 else: 326 reply = json.dumps({"method": "firmware_version_reply", "params": "Unknown"}) 327 self.sendMessage(reply.encode('utf8'))
328 329 @asyncio.coroutine
330 - def get_pinstate_report(self, command):
331 """ 332 This method retrieves a Firmata pin_state report for a pin.. 333 334 See: http://firmata.org/wiki/Protocol#Pin_State_Query 335 336 @param command: {"method": "get_pin_state", "params": [PIN]} 337 @return: {"method": "get_pin_state_reply", "params": [PIN_NUMBER, PIN_MODE, PIN_STATE]} 338 """ 339 pin = int(command[0]) 340 value = yield from self.core.get_pin_state(pin) 341 if value: 342 reply = json.dumps({"method": "pin_state_reply", "params": value}) 343 else: 344 reply = json.dumps({"method": "pin_state_reply", "params": "Unknown"}) 345 self.sendMessage(reply.encode('utf8'))
346 347 @asyncio.coroutine
348 - def get_protocol_version(self):
349 """ 350 This method retrieves the Firmata protocol version. 351 352 JSON command: {"method": "get_protocol_version", "params": ["null"]} 353 354 @return: {"method": "protocol_version_reply", "params": [PROTOCOL_VERSION]} 355 """ 356 value = yield from self.core.get_protocol_version() 357 if value: 358 reply = json.dumps({"method": "protocol_version_reply", "params": value}) 359 else: 360 reply = json.dumps({"method": "protocol_version_reply", "params": "Unknown"}) 361 self.sendMessage(reply.encode('utf8'))
362 363 @asyncio.coroutine
364 - def get_pymata_version(self):
365 """ 366 This method retrieves the PyMata release version number. 367 368 JSON command: {"method": "get_pymata_version", "params": ["null"]} 369 370 @return: {"method": "pymata_version_reply", "params":[PYMATA_VERSION]} 371 """ 372 value = yield from self.core.get_pymata_version() 373 if value: 374 reply = json.dumps({"method": "pymata_version_reply", "params": value}) 375 else: 376 reply = json.dumps({"method": "pymata_version_reply", "params": "Unknown"}) 377 self.sendMessage(reply.encode('utf8'))
378 379 @asyncio.coroutine
380 - def i2c_config(self, command):
381 """ 382 This method initializes the I2c and sets the optional read delay (in microseconds). 383 384 It must be called before doing any other i2c operations for a given device. 385 @param command: {"method": "i2c_config", "params": [DELAY]} 386 @return: No Return message. 387 """ 388 delay = int(command[0]) 389 yield from self.core.i2c_config(delay)
390 391 @asyncio.coroutine
392 - def i2c_read_data(self, command):
393 """ 394 This method retrieves the last value read for an i2c device identified by address. 395 This is a polling implementation and i2c_read_request and i2c_read_request_reply may be 396 a better alternative. 397 @param command: {"method": "i2c_read_data", "params": [I2C_ADDRESS ]} 398 @return:{"method": "i2c_read_data_reply", "params": i2c_data} 399 """ 400 address = int(command[0]) 401 i2c_data = yield from self.core.i2c_read_data(address) 402 reply = json.dumps({"method": "i2c_read_data_reply", "params": i2c_data}) 403 self.sendMessage(reply.encode('utf8'))
404 405 @asyncio.coroutine
406 - def i2c_read_request(self, command):
407 """ 408 This method sends an I2C read request to Firmata. It is qualified by a single shot, continuous 409 read, or stop reading command. 410 Special Note: for the read type supply one of the following strings: 411 412 "I2C_READ" 413 414 "I2C_READ | I2C_END_TX_MASK" 415 416 "I2C_READ_CONTINUOUSLY" 417 418 "I2C_READ_CONTINUOUSLY | I2C_END_TX_MASK" 419 420 @param command: {"method": "i2c_read_request", "params": [I2C_ADDRESS, I2C_REGISTER, 421 NUMBER_OF_BYTES, I2C_READ_TYPE ]} 422 @return: {"method": "i2c_read_request_reply", "params": [DATA]} 423 """ 424 device_address = int(command[0]) 425 register = int(command[1]) 426 number_of_bytes = int(command[2]) 427 428 if command[3] == "I2C_READ_CONTINUOUS": 429 read_type = Constants.I2C_READ_CONTINUOUSLY 430 elif command[3] == "I2C_READ": 431 read_type = Constants.I2C_READ 432 else: 433 read_type = Constants.I2C_STOP_READING 434 yield from self.core.i2c_read_request(device_address, register, number_of_bytes, read_type, 435 self.i2c_read_request_callback)
436 437 @asyncio.coroutine
438 - def i2c_write_request(self, command):
439 """ 440 This method performs an I2C write at a given I2C address, 441 @param command: {"method": "i2c_write_request", "params": [I2C_DEVICE_ADDRESS, [DATA_TO_WRITE]]} 442 @return:No return message. 443 """ 444 device_address = int(command[0]) 445 params = command[1] 446 params = [int(i) for i in params] 447 yield from self.core.i2c_write_request(device_address, *params)
448 449 @asyncio.coroutine
450 - def play_tone(self, command):
451 """ 452 This method controls a piezo device to play a tone. It is a FirmataPlus feature. 453 Tone command is TONE_TONE to play, TONE_NO_TONE to stop playing. 454 @param command: {"method": "play_tone", "params": [PIN, TONE_COMMAND, FREQUENCY(Hz), DURATION(MS)]} 455 @return:No return message. 456 """ 457 pin = int(command[0]) 458 if command[1] == "TONE_TONE": 459 tone_command = Constants.TONE_TONE 460 else: 461 tone_command = Constants.TONE_NO_TONE 462 frequency = int(command[2]) 463 duration = int(command[3]) 464 yield from self.core.play_tone(pin, tone_command, frequency, duration)
465 466 @asyncio.coroutine
467 - def set_analog_latch(self, command):
468 """ 469 This method sets the an analog latch for a given analog pin, providing the threshold type, and 470 latching threshold. 471 @param command: {"method": "set_analog_latch", "params": [PIN, THRESHOLD_TYPE, THRESHOLD_VALUE]} 472 @return:{"method": "analog_latch_data_reply", "params": [PIN, DATA_VALUE_LATCHED, TIMESTAMP_STRING]} 473 """ 474 pin = int(command[0]) 475 threshold_type = int(command[1]) 476 threshold_value = int(command[2]) 477 yield from self.core.set_analog_latch(pin, threshold_type, threshold_value, self.analog_latch_callback)
478 479 @asyncio.coroutine
480 - def set_digital_latch(self, command):
481 """ 482 This method sets the a digital latch for a given digital pin, the threshold type, and latching threshold. 483 @param command:{"method": "set_digital_latch", "params": [PIN, THRESHOLD (0 or 1)]} 484 @return:{"method": digital_latch_data_reply", "params": [PIN, DATA_VALUE_LATCHED, TIMESTAMP_STRING]} 485 """ 486 pin = int(command[0]) 487 threshold_value = int(command[1]) 488 yield from self.core.set_digital_latch(pin, threshold_value, self.digital_latch_callback)
489 490 @asyncio.coroutine
491 - def set_pin_mode(self, command):
492 """ 493 This method sets the pin mode for the selected pin. It handles: Input, Analog(Input) PWM, and OUTPUT. Servo 494 is handled by servo_config(). 495 @param command: {"method": "set_pin_mode", "params": [PIN, MODE]} 496 @return:No return message. 497 """ 498 pin = int(command[0]) 499 mode = int(command[1]) 500 if mode == Constants.INPUT: 501 cb = self.digital_callback 502 elif mode == Constants.ANALOG: 503 cb = self.analog_callback 504 else: 505 cb = None 506 507 yield from self.core.set_pin_mode(pin, mode, cb)
508
509 - def set_sampling_interval(self, command):
510 """ 511 This method sets the Firmata sampling interval in ms. 512 @param command:{"method": "set_sampling_interval", "params": [INTERVAL]} 513 @return:No return message. 514 """ 515 sample_interval = int(command[0]) 516 yield from self.core.set_sampling_interval(sample_interval)
517 518 @asyncio.coroutine
519 - def sonar_config(self, command):
520 """ 521 This method configures 2 pins to support HC-SR04 Ping devices. 522 This is a FirmataPlus feature. 523 @param command: {"method": "sonar_config", "params": [TRIGGER_PIN, ECHO_PIN, PING_INTERVAL(default=50), 524 MAX_DISTANCE(default= 200 cm]} 525 @return:{"method": "sonar_data_reply", "params": [DISTANCE_IN_CM]} 526 """ 527 trigger = int(command[0]) 528 echo = int(command[1]) 529 interval = int(command[2]) 530 max_dist = int(command[3]) 531 yield from self.core.sonar_config(trigger, echo, self.sonar_callback, interval, max_dist)
532 533 @asyncio.coroutine
534 - def sonar_read(self, command):
535 """ 536 This method retrieves the last sonar data value that was cached. 537 This is a polling method. After sonar config, sonar_data_reply messages will be sent automatically. 538 @param command: {"method": "sonar_read", "params": [TRIGGER_PIN]} 539 @return:{"method": "sonar_read_reply", "params": [TRIGGER_PIN, DATA_VALUE]} 540 """ 541 pin = int(command[0]) 542 val = yield from self.core.sonar_data_retrieve(pin) 543 544 reply = json.dumps({"method": "sonar_read_reply", "params": [pin, val]}) 545 self.sendMessage(reply.encode('utf8'))
546 547 @asyncio.coroutine
548 - def servo_config(self, command):
549 """ 550 This method configures a pin for servo operation. The servo angle is set by using analog_write(). 551 @param command: {"method": "servo_config", "params": [PIN, MINIMUM_PULSE(ms), MAXIMUM_PULSE(ms)]} 552 @return:No message returned. 553 """ 554 pin = int(command[0]) 555 min_pulse = int(command[1]) 556 max_pulse = int(command[2]) 557 yield from self.core.servo_config(pin, min_pulse, max_pulse)
558 559 @asyncio.coroutine
560 - def stepper_config(self, command):
561 """ 562 This method configures 4 pins for stepper motor operation. 563 This is a FirmataPlus feature. 564 @param command: {"method": "stepper_config", "params": [STEPS_PER_REVOLUTION, [PIN1, PIN2, PIN3, PIN4]]} 565 @return:No message returned. 566 """ 567 steps_per_revs = int(command[0]) 568 pins = command[1] 569 pin1 = int(pins[0]) 570 pin2 = int(pins[1]) 571 pin3 = int(pins[2]) 572 pin4 = int(pins[3]) 573 yield from self.core.stepper_config(steps_per_revs, [pin1, pin2, pin3, pin4])
574 575 @asyncio.coroutine
576 - def stepper_step(self, command):
577 """ 578 This method activates a stepper motor motion. 579 This is a FirmataPlus feature. 580 @param command: {"method": "stepper_step", "params": [SPEED, NUMBER_OF_STEPS]} 581 @return:No message returned. 582 """ 583 speed = int(command[0]) 584 num_steps = int(command[1]) 585 yield from self.core.stepper_step(speed, num_steps)
586
587 - def onClose(self, was_clean, code, reason):
588 """ 589 Websocket management message. 590 This message is received when the client closes the connection. A console status message is printed and 591 and the interface is shutdown before exiting. 592 @param was_clean: Autobahn provided flag 593 @param code:Autobahn provided flag 594 @param reason:Autobahn provided flag 595 @return:Console message is generated. 596 """ 597 print("WebSocket connection closed: {0}".format(reason)) 598 yield from self.core.shutdown()
599
600 - def onConnect(self, request):
601 """ 602 WebSocket management method. 603 This method issues a console status message for Websocket connection establishment. 604 @param request: Websocket request 605 @return: No return value. 606 """ 607 print("Client connecting: {0}".format(request.peer))
608
609 - def onMessage(self, payload, is_binary):
610 """ 611 Websocket management method. 612 This method receives JSON messages from the Websocket client. All messages are assumed to be text. 613 If a binary message is sent, a console status message is generated. 614 615 The JSON command is interpreted and translated to a method call to handle the command request. 616 @param payload: JSON command 617 @param is_binary: True if message is binary. Assumed to always be False 618 @return: No value is returned. 619 """ 620 if is_binary: 621 print("Binary message received: {0} bytes".format(len(payload))) 622 print('Expected text and not binary') 623 else: 624 cmd_dict = json.loads(payload.decode('utf8')) 625 client_cmd = cmd_dict.get("method") 626 627 if client_cmd in self.command_map: 628 cmd = self.command_map.get(client_cmd) 629 params = cmd_dict.get("params") 630 if params[0] != "null": 631 yield from cmd(params) 632 else: 633 yield from cmd()
634
635 - def onOpen(self):
636 """ 637 WebSocket management method. 638 This method issues a console status message for the opening of a Websocket connection. It sends a Firmata 639 reset command to the Arduino. 640 @return: No return value. 641 """ 642 print("WebSocket connection open.") 643 yield from self.core.send_reset()
644
645 - def analog_callback(self, data):
646 """ 647 This method handles the analog message received from pymata_core 648 @param data: analog callback message 649 @return:{"method": "analog_message_reply", "params": [PIN, DATA_VALUE} 650 """ 651 reply = json.dumps({"method": "analog_message_reply", "params": [data[0], data[1]]}) 652 self.sendMessage(reply.encode('utf8'))
653
654 - def analog_latch_callback(self, data):
655 """ 656 This method handles analog_latch data received from pymata_core 657 @param data: analog latch callback message 658 @return:{"method": "analog_latch_data_reply", "params": [ANALOG_PIN, VALUE_AT_TRIGGER, TIME_STAMP_STRING]} 659 """ 660 ts = data[2] 661 st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') 662 reply = json.dumps({"method": "analog_latch_data_reply", "params": [data[0], data[1], st]}) 663 self.sendMessage(reply.encode('utf8'))
664
665 - def digital_callback(self, data):
666 """ 667 This method handles the digital message received from pymata_core 668 @param data: digital callback message 669 @return:{"method": "digital_message_reply", "params": [PIN, DATA_VALUE]} 670 """ 671 reply = json.dumps({"method": "digital_message_reply", "params": [data[0], data[1]]}) 672 self.sendMessage(reply.encode('utf8'))
673 # yield from self.core.sleep(.001) 674
675 - def digital_latch_callback(self, data):
676 """ 677 This method handles the digital latch data message received from pymata_core 678 @param data: digital latch callback message 679 @return:s{"method": "digital_latch_data_reply", "params": [PIN, DATA_VALUE_AT_TRIGGER, TIME_STAMP_STRING]} 680 """ 681 ts = data[2] 682 st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S') 683 reply = json.dumps({"method": "digital_latch_data_reply", "params": [data[0], data[1], st]}) 684 self.sendMessage(reply.encode('utf8'))
685
686 - def encoder_callback(self, data):
687 """ 688 This method handles the encoder data message received from pymata_core 689 @param data: encoder data callback message 690 @return:{"method": "encoder_data_reply", "params": [ENCODER VALUE]} 691 """ 692 reply = json.dumps({"method": "encoder_data_reply", "params": data}) 693 self.sendMessage(reply.encode('utf8'))
694
695 - def i2c_read_request_callback(self, data):
696 """ 697 This method handles the i2c read data message received from pymata_core. 698 @param data: i2c read data callback message 699 @return:{"method": "i2c_read_request_reply", "params": [DATA_VALUE]} 700 """ 701 reply = json.dumps({"method": "i2c_read_request_reply", "params": data}) 702 self.sendMessage(reply.encode('utf8'))
703
704 - def i2c_read_data_callback(self, data):
705 """ 706 This method handles the i2c cached read data received from pymata_core. 707 @param data: i2c read cached data callback message 708 @return:{"method": "i2c_read_data_reply", "params": [DATA_VALUE]} 709 """ 710 reply = json.dumps({"method": "i2c_read_data_reply", "params": data}) 711 self.sendMessage(reply.encode('utf8'))
712
713 - def sonar_callback(self, data):
714 """ 715 This method handles sonar data received from pymata_core. 716 @param data: sonar data callback message 717 @return:{"method": "sonar_data_reply", "params": [DATA_VALUE]} 718 """ 719 reply = json.dumps({"method": "sonar_data_reply", "params": data}) 720 721 self.sendMessage(reply.encode('utf8'))
722 723 724 if __name__ == '__main__': 725 726 # factory = WebSocketServerFactory("ws://localhost:9000", debug=False) 727 ws_string = 'ws://' + PymataIOT.ip_addr + ':' + PymataIOT.ip_port 728 print('Websocket server operating on: ' + ws_string) 729 factory = WebSocketServerFactory(ws_string, debug=False) 730 factory.protocol = PymataIOT 731 732 loop = asyncio.get_event_loop() 733 # coro = loop.create_server(factory, '0.0.0.0', 9000) 734 coro = loop.create_server(factory, '0.0.0.0', int(PymataIOT.ip_port)) 735 server = loop.run_until_complete(coro) 736 737 try: 738 loop.run_forever() 739 except KeyboardInterrupt: 740 pass 741 finally: 742 server.close() 743 loop.close() 744