Add Code
This commit is contained in:
17
code/.venv/lib/python3.12/site-packages/pyboard/__init__.py
Normal file
17
code/.venv/lib/python3.12/site-packages/pyboard/__init__.py
Normal file
@@ -0,0 +1,17 @@
|
||||
"""
|
||||
Copyright (c) 2018-2019 Kaiyu Liu All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3 as published by the Free Software Foundation; either
|
||||
or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
"""
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
914
code/.venv/lib/python3.12/site-packages/pyboard/board.py
Normal file
914
code/.venv/lib/python3.12/site-packages/pyboard/board.py
Normal file
@@ -0,0 +1,914 @@
|
||||
"""
|
||||
Copyright (c) 2018-2019 Kaiyu Liu,, All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3 as published by the Free Software Foundation; either
|
||||
or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
import os
|
||||
import asyncio
|
||||
from pymata_aio.constants import Constants
|
||||
|
||||
try:
|
||||
from pyboard_core import PyBoardCore
|
||||
except ImportError:
|
||||
from .pyboard_core import PyBoardCore
|
||||
|
||||
|
||||
class PyBoard(Constants):
|
||||
"""
|
||||
This class exposes and implements a proxy API for the pymata_core asyncio
|
||||
API, If your application does not use asyncio directly, this is
|
||||
the API that you should use.
|
||||
"""
|
||||
|
||||
def __init__(self, com_port=None, arduino_wait=2, sleep_tune=0.0001, log_output=False,
|
||||
ip_address=None, ip_port=2000, ip_handshake='*HELLO*'):
|
||||
"""
|
||||
Constructor for the PyBoard API
|
||||
If log_output is set to True, a log file called 'pymata_log'
|
||||
will be created in the current directory and all pymata_aio output
|
||||
will be redirected to the log with no output appearing on the console.
|
||||
|
||||
:param arduino_wait: Amount of time to allow Arduino to finish its
|
||||
reset (2 seconds for Uno, Leonardo can be 0)
|
||||
|
||||
:param sleep_tune: This parameter sets the amount of time PyMata core
|
||||
uses to set asyncio.sleep
|
||||
|
||||
:param log_output: If True, pymata_aio.log is created and all
|
||||
console output is redirected to this file.
|
||||
|
||||
:param com_port: If specified, auto port detection will not be
|
||||
performed and this com port will be used.
|
||||
|
||||
:param ip_address: If using a WiFly module, set its address here
|
||||
|
||||
:param ip_port: Port to used with ip_address
|
||||
|
||||
:param ip_handshake: Connectivity handshake string sent by IP device
|
||||
|
||||
:returns: None
|
||||
"""
|
||||
self.log_out = log_output
|
||||
self.loop = asyncio.get_event_loop()
|
||||
|
||||
self.sleep_tune = sleep_tune
|
||||
self.core = PyBoardCore(arduino_wait, self.sleep_tune, log_output,
|
||||
com_port, ip_address, ip_port, ip_handshake)
|
||||
os.system('cls||clear')
|
||||
self.core.start()
|
||||
|
||||
self.sleep(1)
|
||||
|
||||
def analogRead(self, pin):
|
||||
"""
|
||||
Retrieve the last data update for the specified analog pin.
|
||||
It is intended for a polling application.
|
||||
|
||||
:param pin: Analog pin number (ex. A2 is specified as 2)
|
||||
|
||||
:returns: Last value reported for the analog pin
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.analog_read(pin))
|
||||
value = self.loop.run_until_complete(task)
|
||||
return value
|
||||
|
||||
def analogWrite(self, pin, value):
|
||||
"""
|
||||
Set the selected PWM pin to the specified value.
|
||||
|
||||
:param pin: PWM pin number
|
||||
|
||||
:param value: Set the selected pin to the specified
|
||||
value. 0-0x4000 (14 bits)
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.analog_write(pin, value))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def digitalRead(self, pin):
|
||||
"""
|
||||
Retrieve the last data update for the specified digital pin.
|
||||
It is intended for a polling application.
|
||||
|
||||
:param pin: Digital pin number
|
||||
|
||||
:returns: Last value reported for the digital pin
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.digital_read(pin))
|
||||
value = self.loop.run_until_complete(task)
|
||||
return value
|
||||
|
||||
def digitalPinWrite(self, pin, value=0):
|
||||
"""
|
||||
Set the specified digital input pin to the provided value
|
||||
|
||||
:param pin: Digital pin to be set
|
||||
|
||||
:param value: 0 or 1
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.digital_pin_write(pin, value))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def digitalWrite(self, pin, value=0):
|
||||
"""
|
||||
Set the specified digital input pin to the provided value
|
||||
|
||||
:param pin: Digital pin to be set
|
||||
|
||||
:param value: 0 or 1
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.digital_write(pin, value))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def disableAnalogReporting(self, pin):
|
||||
"""
|
||||
Disables analog reporting for a single analog pin.
|
||||
|
||||
:param pin: Analog pin number. For example for A0, the number is 0.
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.disable_analog_reporting(pin))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def disableDigitalReporting(self, pin):
|
||||
"""
|
||||
Disables digital reporting. By turning reporting off for this pin,
|
||||
reporting is disabled for all 8 bits in the "port"
|
||||
|
||||
:param pin: Pin and all pins for this port
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.disable_digital_reporting(pin))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def configEncoder(self, pin_a, pin_b, cb=None, cb_type=None,
|
||||
hall_encoder=False):
|
||||
"""
|
||||
This command enables the rotary encoder (2 pin + ground) and will
|
||||
enable encoder reporting.
|
||||
|
||||
This is a FirmataPlus feature.
|
||||
|
||||
Encoder data is retrieved by performing a digital_read from
|
||||
pin a (encoder pin 1)
|
||||
|
||||
:param pin_a: Encoder pin 1.
|
||||
|
||||
:param pin_b: Encoder pin 2.
|
||||
|
||||
:param cb: callback function to report encoder changes
|
||||
|
||||
:param cb_type: Constants.CB_TYPE_DIRECT = direct call
|
||||
or Constants.CB_TYPE_ASYNCIO = asyncio coroutine
|
||||
|
||||
:param hall_encoder: wheel hall_encoder - set to True to select
|
||||
hall encoder support support.
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.encoder_config(pin_a, pin_b,
|
||||
cb, cb_type,
|
||||
hall_encoder))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def encoderRead(self, pin):
|
||||
"""
|
||||
This method retrieves the latest encoder data value.
|
||||
It is a FirmataPlus feature.
|
||||
|
||||
:param pin: Encoder Pin
|
||||
|
||||
:returns: encoder data value
|
||||
"""
|
||||
try:
|
||||
task = asyncio.ensure_future(self.core.encoder_read(pin))
|
||||
value = self.loop.run_until_complete(task)
|
||||
return value
|
||||
except RuntimeError:
|
||||
self.shutdown()
|
||||
|
||||
def enableAnalogReporting(self, pin):
|
||||
"""
|
||||
Enables analog reporting for a single analog pin,
|
||||
|
||||
:param pin: Analog pin number. For example for A0, the number is 0.
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.enable_analog_reporting(pin))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def enableDigitalReporting(self, pin):
|
||||
"""
|
||||
Enables digital reporting. By turning reporting on for all
|
||||
8 bits in the "port".
|
||||
This is part of Firmata's protocol specification.
|
||||
|
||||
:param pin: Pin and all pins for this port
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.enable_digital_reporting(pin))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def extendedAnalog(self, pin, data):
|
||||
"""
|
||||
This method will send an extended-data analog write command
|
||||
to the selected pin..
|
||||
|
||||
:param pin: 0 - 127
|
||||
|
||||
:param data: 0 - 0-0x4000 (14 bits)
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.extended_analog(pin, data))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def getAnalogLatchData(self, pin):
|
||||
"""
|
||||
A list is returned containing the latch state for the pin, the
|
||||
latched value, and the time stamp
|
||||
[pin_num, latch_state, latched_value, time_stamp]
|
||||
If the the latch state is LATCH_LATCHED, the table is reset
|
||||
(data and timestamp set to zero)
|
||||
It is intended to be used for a polling application.
|
||||
|
||||
:param pin: Pin number.
|
||||
|
||||
:returns: [latched_state, threshold_type, threshold_value,
|
||||
latched_data, time_stamp]
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_analog_latch_data(pin))
|
||||
l_data = self.loop.run_until_complete(task)
|
||||
return l_data
|
||||
|
||||
def getAnalogMap(self, cb=None):
|
||||
"""
|
||||
This method requests and returns an analog map.
|
||||
|
||||
:param cb: Optional callback reference
|
||||
|
||||
:returns: An analog map response or None if a timeout occurs
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_analog_map())
|
||||
report = self.loop.run_until_complete(task)
|
||||
if cb:
|
||||
cb(report)
|
||||
else:
|
||||
return report
|
||||
|
||||
def getCapabilityReport(self, raw=True, cb=None):
|
||||
"""
|
||||
This method retrieves the Firmata capability report
|
||||
|
||||
:param raw: If True, it either stores or provides the callback
|
||||
with a report as list.
|
||||
If False, prints a formatted report to the console
|
||||
|
||||
:param cb: Optional callback reference to receive a raw report
|
||||
|
||||
:returns: capability report
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_capability_report())
|
||||
report = self.loop.run_until_complete(task)
|
||||
if raw:
|
||||
if cb:
|
||||
cb(report)
|
||||
else:
|
||||
return report
|
||||
else:
|
||||
# noinspection PyProtectedMember
|
||||
self.core._format_capability_report(report)
|
||||
|
||||
def getDigitalLatchData(self, pin):
|
||||
"""
|
||||
A list is returned containing the latch state for the pin, the
|
||||
latched value, and the time stamp
|
||||
|
||||
[pin_num, latch_state, latched_value, time_stamp]
|
||||
|
||||
If the the latch state is LATCH_LATCHED, the table is reset
|
||||
(data and timestamp set to zero).
|
||||
It is intended for use by a polling application.
|
||||
|
||||
:param pin: Pin number.
|
||||
|
||||
:returns: [latched_state, threshold_type, threshold_value,
|
||||
latched_data, time_stamp]
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_digital_latch_data(pin))
|
||||
l_data = self.loop.run_until_complete(task)
|
||||
return l_data
|
||||
|
||||
def getFirmwareVersion(self, cb=None):
|
||||
"""
|
||||
This method retrieves the Firmata firmware version
|
||||
|
||||
:param cb: Reference to a callback function
|
||||
|
||||
:returns:If no callback is specified, the firmware version
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_firmware_version())
|
||||
version = self.loop.run_until_complete(task)
|
||||
if cb:
|
||||
cb(version)
|
||||
else:
|
||||
return version
|
||||
|
||||
def getProtocolVersion(self, cb=None):
|
||||
"""
|
||||
This method retrieves the Firmata protocol version
|
||||
|
||||
:param cb: Optional callback reference.
|
||||
|
||||
:returns:If no callback is specified, the firmware version
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_protocol_version())
|
||||
version = self.loop.run_until_complete(task)
|
||||
|
||||
if cb:
|
||||
cb(version)
|
||||
else:
|
||||
return version
|
||||
|
||||
def getPinState(self, pin, cb=None):
|
||||
"""
|
||||
This method retrieves a pin state report for the specified pin
|
||||
|
||||
:param pin: Pin of interest
|
||||
|
||||
:param cb: optional callback reference
|
||||
|
||||
:returns: pin state report
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_pin_state(pin))
|
||||
report = self.loop.run_until_complete(task)
|
||||
|
||||
if cb:
|
||||
cb(report)
|
||||
else:
|
||||
return report
|
||||
|
||||
def get_pymata_version(self):
|
||||
"""
|
||||
This method retrieves the firmata version number
|
||||
|
||||
:returns: PyMata version number.
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.get_pymata_version())
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def configI2C(self, read_delay_time=0):
|
||||
"""
|
||||
This method configures Arduino i2c with an optional read delay time.
|
||||
|
||||
:param read_delay_time: firmata i2c delay time
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.i2c_config(read_delay_time))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def readI2CData(self, address):
|
||||
"""
|
||||
Retrieve result of last data read from i2c device.
|
||||
i2c_read_request should be called before trying to retrieve data.
|
||||
It is intended for use by a polling application.
|
||||
|
||||
:param address: i2c
|
||||
|
||||
:returns: last data read or None if no data is present.
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.i2c_read_data(address))
|
||||
value = self.loop.run_until_complete(task)
|
||||
return value
|
||||
|
||||
def readI2CRequest(self, address, register, number_of_bytes, read_type,
|
||||
cb=None, cb_type=None):
|
||||
"""
|
||||
This method issues an i2c read request for a single read,continuous
|
||||
read or a stop, specified by the read_type.
|
||||
Because different i2c devices return data at different rates,
|
||||
if a callback is not specified, the user must first call this method
|
||||
and then call i2c_read_data after waiting for sufficient time for the
|
||||
i2c device to respond.
|
||||
Some devices require that transmission be restarted
|
||||
(e.g. MMA8452Q accelerometer).
|
||||
Use I2C_READ | I2C_RESTART_TX for those cases.
|
||||
|
||||
:param address: i2c device
|
||||
|
||||
:param register: i2c register number
|
||||
|
||||
:param number_of_bytes: number of bytes to be returned
|
||||
|
||||
:param read_type: Constants.I2C_READ, Constants.I2C_READ_CONTINUOUSLY
|
||||
or Constants.I2C_STOP_READING.
|
||||
|
||||
Constants.I2C_RESTART_TX may be OR'ed when required
|
||||
:param cb: optional callback reference
|
||||
|
||||
:param cb_type: Constants.CB_TYPE_DIRECT = direct call or
|
||||
Constants.CB_TYPE_ASYNCIO = asyncio coroutine
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
|
||||
task = asyncio.ensure_future(self.core.i2c_read_request(address, register,
|
||||
number_of_bytes,
|
||||
read_type,
|
||||
cb,
|
||||
cb_type))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def writeI2CRequest(self, address, args):
|
||||
"""
|
||||
Write data to an i2c device.
|
||||
|
||||
:param address: i2c device address
|
||||
|
||||
:param args: A variable number of bytes to be sent to the device
|
||||
passed in as a list.
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.i2c_write_request(address, args))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def keepAlive(self, period=1, margin=.3):
|
||||
"""
|
||||
Periodically send a keep alive message to the Arduino.
|
||||
Frequency of keep alive transmission is calculated as follows:
|
||||
keep_alive_sent = period - (period * margin)
|
||||
|
||||
|
||||
:param period: Time period between keepalives.
|
||||
Range is 0-10 seconds. 0 disables
|
||||
the keepalive mechanism.
|
||||
|
||||
:param margin: Safety margin to assure keepalives
|
||||
are sent before period expires. Range is 0.1 to 0.9
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
asyncio.ensure_future(self.core.keep_alive(period, margin))
|
||||
|
||||
def playTone(self, pin, tone_command, frequency, duration=None):
|
||||
"""
|
||||
This method will call the Tone library for the selected pin.
|
||||
It requires FirmataPlus to be loaded onto the arduino
|
||||
|
||||
If the tone command is set to TONE_TONE, then the specified
|
||||
tone will be played.
|
||||
|
||||
Else, if the tone command is TONE_NO_TONE, then any currently
|
||||
playing tone will be disabled.
|
||||
|
||||
|
||||
:param pin: Pin number
|
||||
|
||||
:param tone_command: Either TONE_TONE, or TONE_NO_TONE
|
||||
|
||||
:param frequency: Frequency of tone
|
||||
|
||||
:param duration: Duration of tone in milliseconds
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.play_tone(pin, tone_command,
|
||||
frequency, duration))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def tone(self, pin, frequency, duration=None):
|
||||
return playTone(self, pin, Constant.TONE_TONE, frequency, duration);
|
||||
|
||||
def noTone(self, pin):
|
||||
return playTone(self, pin, Constant.TONE_NO_TONE, 0);
|
||||
|
||||
|
||||
def sendReset(self):
|
||||
"""
|
||||
Send a Firmata reset command
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.send_reset())
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def configServo(self, pin, min_pulse=544, max_pulse=2400):
|
||||
"""
|
||||
This method configures the Arduino for servo operation.
|
||||
|
||||
:param pin: Servo control pin
|
||||
|
||||
:param min_pulse: Minimum pulse width
|
||||
|
||||
:param max_pulse: Maximum pulse width
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.servo_config(pin, min_pulse,
|
||||
max_pulse))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def setAnalogLatch(self, pin, threshold_type, threshold_value,
|
||||
cb=None, cb_type=None):
|
||||
"""
|
||||
This method "arms" an analog pin for its data to be latched and
|
||||
saved in the latching table.
|
||||
If a callback method is provided, when latching criteria is achieved,
|
||||
the callback function is called with latching data notification.
|
||||
|
||||
:param pin: Analog pin number (value following an 'A' designator,
|
||||
i.e. A5 = 5
|
||||
|
||||
:param threshold_type: Constants.LATCH_GT | Constants.LATCH_LT |
|
||||
Constants.LATCH_GTE | Constants.LATCH_LTE
|
||||
|
||||
:param threshold_value: numerical value - between 0 and 1023
|
||||
|
||||
:param cb: callback method
|
||||
|
||||
:param cb_type: Constants.CB_TYPE_DIRECT = direct call or
|
||||
Constants.CB_TYPE_ASYNCIO = asyncio coroutine
|
||||
|
||||
:returns: True if successful, False if parameter data is invalid
|
||||
"""
|
||||
|
||||
task = asyncio.ensure_future(self.core.set_analog_latch(pin, threshold_type, threshold_value, cb, cb_type))
|
||||
result = self.loop.run_until_complete(task)
|
||||
return result
|
||||
|
||||
def setDigitalLatch(self, pin, threshold_value, cb=None, cb_type=None):
|
||||
"""
|
||||
This method "arms" a digital pin for its data to be latched and saved
|
||||
in the latching table.
|
||||
If a callback method is provided, when latching criteria is achieved,
|
||||
the callback function is called
|
||||
with latching data notification.
|
||||
|
||||
:param pin: Digital pin number
|
||||
|
||||
:param threshold_value: 0 or 1
|
||||
|
||||
:param cb: callback function
|
||||
|
||||
:param cb_type: Constants.CB_TYPE_DIRECT = direct call or
|
||||
Constants.CB_TYPE_ASYNCIO = asyncio coroutine
|
||||
|
||||
:returns: True if successful, False if parameter data is invalid
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.set_digital_latch(pin, threshold_value, cb, cb_type))
|
||||
result = self.loop.run_until_complete(task)
|
||||
return result
|
||||
|
||||
def pinMode(self, pin_number, pin_state, callback=None, cb_type=None):
|
||||
"""
|
||||
This method sets the pin mode for the specified pin.
|
||||
|
||||
:param pin_number: Arduino Pin Number
|
||||
|
||||
:param pin_state: INPUT/OUTPUT/ANALOG/PWM/PULLUP - for SERVO use
|
||||
servo_config()
|
||||
|
||||
:param callback: Optional: A reference to a call back function to be
|
||||
called when pin data value changes
|
||||
|
||||
:param cb_type: Constants.CB_TYPE_DIRECT = direct call or
|
||||
Constants.CB_TYPE_ASYNCIO = asyncio coroutine
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.set_pin_mode(pin_number, pin_state, callback, cb_type))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def setSamplingInterval(self, interval):
|
||||
"""
|
||||
This method sets the sampling interval for the Firmata loop method
|
||||
|
||||
:param interval: time in milliseconds
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.set_sampling_interval(interval))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def delay(self, milliseconds):
|
||||
"""
|
||||
Perform an asyncio sleep for the time specified in milliseconds.
|
||||
|
||||
:param milliseconds: time in milliseconds
|
||||
:returns: No return value
|
||||
"""
|
||||
self.sleep(milliseconds * 0.001)
|
||||
|
||||
def sleep(self, time):
|
||||
"""
|
||||
Perform an asyncio sleep for the time specified in seconds. T
|
||||
his method should be used in place of time.sleep()
|
||||
|
||||
:param time: time in seconds
|
||||
:returns: No return value
|
||||
"""
|
||||
try:
|
||||
task = asyncio.ensure_future(self.core.sleep(time))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
except asyncio.CancelledError:
|
||||
pass
|
||||
except RuntimeError:
|
||||
pass
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
Shutdown the application and exit
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.shutdown())
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
def configSonar(self, trigger_pin, echo_pin, cb=None, ping_interval=50,
|
||||
max_distance=200, cb_type=None):
|
||||
"""
|
||||
Configure the pins,ping interval and maximum distance for an HC-SR04
|
||||
type device.
|
||||
Single pin configuration may be used. To do so, set both the trigger
|
||||
and echo pins to the same value.
|
||||
Up to a maximum of 6 SONAR devices is supported
|
||||
If the maximum is exceeded a message is sent to the console and the
|
||||
request is ignored.
|
||||
NOTE: data is measured in centimeters
|
||||
|
||||
This is FirmataPlus feature.
|
||||
|
||||
:param trigger_pin: The pin number of for the trigger (transmitter).
|
||||
|
||||
:param echo_pin: The pin number for the received echo.
|
||||
|
||||
:param cb: optional callback function to report sonar data changes
|
||||
|
||||
:param ping_interval: Minimum interval between pings. Lowest number
|
||||
to use is 33 ms.Max is 127
|
||||
|
||||
:param max_distance: Maximum distance in cm. Max is 200.
|
||||
|
||||
:param cb_type: direct call or asyncio yield from
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.sonar_config(trigger_pin,
|
||||
echo_pin, cb,
|
||||
ping_interval,
|
||||
max_distance, cb_type))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def getDataFromSonar(self, trigger_pin, waitTime = 500):
|
||||
"""
|
||||
Retrieve Ping (HC-SR04 type) data. The data is presented as a
|
||||
dictionary.
|
||||
The 'key' is the trigger pin specified in sonar_config() and the
|
||||
'data' is the current measured distance (in centimeters)
|
||||
for that pin. If there is no data, the value is set to None.
|
||||
This is a FirmataPlus feature.
|
||||
|
||||
:param trigger_pin: trigger pin specified in sonar_config
|
||||
|
||||
:returns: active_sonar_map
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.ping_read(trigger_pin))
|
||||
self.loop.run_until_complete(task)
|
||||
if(waitTime < 200):
|
||||
waitTime = 200
|
||||
self.delay(waitTime)
|
||||
task = asyncio.ensure_future(self.core.ping_data_retrieve(trigger_pin))
|
||||
sonar_data = self.loop.run_until_complete(task)
|
||||
return sonar_data
|
||||
|
||||
def configStepper(self, steps_per_revolution, stepper_pins):
|
||||
"""
|
||||
Configure stepper motor prior to operation.
|
||||
This is a FirmataPlus feature.
|
||||
|
||||
:param steps_per_revolution: number of steps per motor revolution
|
||||
|
||||
:param stepper_pins: a list of control pin numbers - either 4 or 2
|
||||
|
||||
:returns: No return value
|
||||
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.stepper_config(steps_per_revolution,
|
||||
stepper_pins))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def stepStepper(self, motor_speed, number_of_steps):
|
||||
"""
|
||||
Move a stepper motor for the number of steps at the specified speed
|
||||
This is a FirmataPlus feature.
|
||||
|
||||
:param motor_speed: 21 bits of data to set motor speed
|
||||
|
||||
:param number_of_steps: 14 bits for number of steps & direction
|
||||
positive is forward, negative is reverse
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.stepper_step(motor_speed,
|
||||
number_of_steps))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def configNeopixel(self, pin, count=12, brightness=128):
|
||||
"""
|
||||
Configure Neopixel strip prior to operation.
|
||||
This is an extended firmata feature.
|
||||
|
||||
:param pin: data pin of the neopixel strip
|
||||
|
||||
:param count: number of pixels in strip
|
||||
|
||||
:param brightnessss: brigheness of the pixels
|
||||
|
||||
:returns: No return value
|
||||
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.neopixel_config(pin, count, brightness))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def setNeopixelColor(self, index, r, g, b):
|
||||
"""
|
||||
Set the color of the pixel at specified index.
|
||||
This is an extended firmata feature.
|
||||
|
||||
:param index: position of the pixel to set the color
|
||||
|
||||
:param r: red value of the pixel color
|
||||
|
||||
:param g: green value of the pixel color
|
||||
|
||||
:param b: blue value of the pixel color
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.neopixel(index,r, g, b))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def configLCD(self, address=0x3F, row=2, col=16):
|
||||
"""
|
||||
Configure LCD1602 using I2C.
|
||||
This is an extended firmata feature.
|
||||
|
||||
:param address: I2C adddress of the LCD
|
||||
|
||||
:param row: number of rows on the LCD
|
||||
|
||||
:param col: number of chars on each row
|
||||
|
||||
:returns: No return value
|
||||
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.lcd_config(address, col, row))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def printOnLCD(self, text, row = 0, col = 0, backlight=True):
|
||||
"""
|
||||
Show specifiedd text on the LCD.
|
||||
This is an extended firmata feature.
|
||||
|
||||
:param address: I2C adddress of the LCD
|
||||
|
||||
:param row: on which row to show the text
|
||||
|
||||
:param col: from which character to print the text
|
||||
|
||||
:returns: No return value
|
||||
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.lcd_print(text, row, col, backlight))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def clearLCD(self):
|
||||
"""
|
||||
Clear the LCD screen.
|
||||
This is an extended firmata feature.
|
||||
|
||||
:returns: No return value
|
||||
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.lcd_clear())
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def configDHT(self, pin):
|
||||
"""
|
||||
Configure a DHT device.
|
||||
This is an extended firmata feature.
|
||||
|
||||
:param pin: data pin of the DHT11
|
||||
|
||||
:returns: No return value
|
||||
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.dht_read(pin))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def getDataFromDHT(self, pin, waitTime=500):
|
||||
"""
|
||||
Read the value from a DHT device.
|
||||
This is an extended firmata feature.
|
||||
|
||||
:param pin: data pin of the DHT11
|
||||
|
||||
:returns: No return value
|
||||
|
||||
"""
|
||||
if(waitTime < 100):
|
||||
waitTime = 100
|
||||
self.delay(waitTime)
|
||||
task = asyncio.ensure_future(self.core.dht_data_retrieve(pin))
|
||||
dhtdata = self.loop.run_until_complete(task)
|
||||
return dhtdata
|
||||
|
||||
def pixyInit(self, max_blocks=5, cb=None, cb_type=None):
|
||||
"""
|
||||
Initialize Pixy and will enable Pixy block reporting.
|
||||
This is a FirmataPlusRB feature.
|
||||
|
||||
:param cb: callback function to report Pixy blocks
|
||||
|
||||
:param cb_type: Constants.CB_TYPE_DIRECT = direct call or
|
||||
Constants.CB_TYPE_ASYNCIO = asyncio coroutine
|
||||
|
||||
:param max_blocks: Maximum number of Pixy blocks to report when many
|
||||
signatures are found.
|
||||
|
||||
:returns: No return value.
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.pixy_init(max_blocks, cb, cb_type))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def pixyGetBlocks(self):
|
||||
"""
|
||||
This method retrieves the latest Pixy data value
|
||||
|
||||
:returns: Pixy data
|
||||
"""
|
||||
return self.core.pixy_blocks
|
||||
|
||||
def pixySetServos(self, s0, s1):
|
||||
"""
|
||||
Sends the setServos Pixy command.
|
||||
This method sets the pan/tilt servos that are plugged into Pixy's two servo ports.
|
||||
|
||||
:param s0: value 0 to 1000
|
||||
|
||||
:param s1: value 0 to 1000
|
||||
|
||||
:returns: No return value.
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.pixy_set_servos(s0, s1))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def pixySetBrightness(self, brightness):
|
||||
"""
|
||||
Sends the setBrightness Pixy command.
|
||||
This method sets the brightness (exposure) of Pixy's camera.
|
||||
|
||||
:param brightness: range between 0 and 255 with 255 being the
|
||||
brightest setting
|
||||
|
||||
:returns: No return value.
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.pixy_set_brightness(brightness))
|
||||
self.loop.run_until_complete(task)
|
||||
|
||||
def pixySetLed(self, r, g, b):
|
||||
"""
|
||||
Sends the setLed Pixy command.
|
||||
This method sets the RGB LED on front of Pixy.
|
||||
|
||||
:param r: red range between 0 and 255
|
||||
|
||||
:param g: green range between 0 and 255
|
||||
|
||||
:param b: blue range between 0 and 255
|
||||
|
||||
:returns: No return value.
|
||||
"""
|
||||
task = asyncio.ensure_future(self.core.pixy_set_led(r, g, b))
|
||||
self.loop.run_until_complete(task)
|
||||
19
code/.venv/lib/python3.12/site-packages/pyboard/main.py
Normal file
19
code/.venv/lib/python3.12/site-packages/pyboard/main.py
Normal file
@@ -0,0 +1,19 @@
|
||||
"""
|
||||
Copyright (c) 2018-2019 Kaiyu Liu All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3 as published by the Free Software Foundation; either
|
||||
or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
"""
|
||||
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
|
||||
import pyboard.pyboard_core.PyBoardCore
|
||||
@@ -0,0 +1,31 @@
|
||||
"""
|
||||
Copyright (c) 2018-2019 Kaiyu Liu,, All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3 as published by the Free Software Foundation; either
|
||||
or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
from pymata_aio.private_constants import PrivateConstants
|
||||
|
||||
class BoardConstants(PrivateConstants):
|
||||
NEOPIXEL_CONFIG = 0xA2
|
||||
NEOPIXEL = 0xA0
|
||||
LCD_CONFIG = 0xA4
|
||||
LCD_PRINT = 0xA5
|
||||
LCD_CLEAR = 0xA6
|
||||
DHT11_READ = 0xA7
|
||||
DHT11_DATA = 0xA8
|
||||
PING_READ = 0xA9
|
||||
PING_DATA = 0xAA
|
||||
|
||||
def __init__():
|
||||
PrivateConstants.__init__()
|
||||
213
code/.venv/lib/python3.12/site-packages/pyboard/pyboard_core.py
Normal file
213
code/.venv/lib/python3.12/site-packages/pyboard/pyboard_core.py
Normal file
@@ -0,0 +1,213 @@
|
||||
"""
|
||||
Copyright (c) 2018-2019 Kaiyu Liu, All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3 as published by the Free Software Foundation; either
|
||||
or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
# noinspection PyCompatibility
|
||||
import asyncio
|
||||
import glob
|
||||
import logging
|
||||
import sys
|
||||
import time
|
||||
|
||||
# noinspection PyPackageRequirements
|
||||
import serial
|
||||
from pymata_aio.pymata_core import PymataCore
|
||||
from pymata_aio.pin_data import PinData
|
||||
#from pymata_aio.private_constants import PrivateConstants
|
||||
from pymata_aio.pymata_serial import PymataSerial
|
||||
from pymata_aio.pymata_socket import PymataSocket
|
||||
try:
|
||||
from pyboard_constants import BoardConstants
|
||||
except ImportError:
|
||||
from .pyboard_constants import BoardConstants
|
||||
|
||||
|
||||
|
||||
# noinspection PyCallingNonCallable,PyCallingNonCallable,PyPep8,PyBroadException,PyBroadException,PyCompatibility
|
||||
class PyBoardCore(PymataCore):
|
||||
"""
|
||||
This class exposes and implements the pymata_core asyncio API,
|
||||
It includes the public API methods as well as
|
||||
a set of private methods. If your application is using asyncio,
|
||||
this is the API that you should use.
|
||||
|
||||
After instantiating this class, its "start" method MUST be called to
|
||||
perform Arduino pin auto-detection.
|
||||
"""
|
||||
|
||||
def __init__(self, arduino_wait=2, sleep_tune=0.0001, log_output=False,com_port=None,
|
||||
ip_address=None, ip_port=2000,
|
||||
ip_handshake='*HELLO*'):
|
||||
PymataCore.__init__(self, arduino_wait, sleep_tune, log_output, com_port, ip_address, ip_port,ip_handshake)
|
||||
|
||||
# report query results are stored in this dictionary
|
||||
self.query_reply_data[BoardConstants.DHT11_DATA] = None
|
||||
self.command_dictionary[BoardConstants.DHT11_DATA] = self._dht_data
|
||||
self.command_dictionary[BoardConstants.PING_DATA] = self._ping_data
|
||||
self.dht_map = {}
|
||||
self.ping_map = {}
|
||||
|
||||
async def neopixel_config(self, pin, count=12, brightness=64):
|
||||
"""
|
||||
Configure a pin as a neopixel pin. Set LED count and brightness.
|
||||
Use this method (not set_pin_mode) to configure a pin for neopixel
|
||||
operation.
|
||||
|
||||
:param pin: neopixel Pin.
|
||||
|
||||
:param count: number of LEDs on the strip.
|
||||
|
||||
:param brightness: brightness from 1 to 255.
|
||||
|
||||
:returns: No return value
|
||||
"""
|
||||
command = [pin, count & 0x7f, (count >> 7) & 0x7f, brightness & 0x7f, (brightness >> 7) & 0x7f]
|
||||
|
||||
await self._send_sysex(BoardConstants.NEOPIXEL_CONFIG, command)
|
||||
|
||||
async def neopixel(self, index, r, g, b):
|
||||
"""
|
||||
Set the color of the LED specified by index.
|
||||
|
||||
:param index: index of the LED
|
||||
|
||||
:param r: red
|
||||
|
||||
:param g: green
|
||||
|
||||
:param b: blue
|
||||
|
||||
:returns: No return value.
|
||||
"""
|
||||
data = [index & 0x7f, (index >> 7) & 0x7f, r & 0x7f, (r >> 7) & 0x7f, g & 0x7f, (g >> 7) & 0x7f, b & 0x7f, (b >> 7) & 0x7f]
|
||||
await self._send_sysex(BoardConstants.NEOPIXEL, data)
|
||||
|
||||
async def lcd_config(self, address, row = 2, col = 16):
|
||||
"""
|
||||
:returns: No return value
|
||||
"""
|
||||
command = [address, col & 0x7f, row & 0x7f]
|
||||
|
||||
await self._send_sysex(BoardConstants.LCD_CONFIG, command)
|
||||
|
||||
async def lcd_print(self, text, row, col, backlight=True):
|
||||
"""
|
||||
:returns: No return value.
|
||||
"""
|
||||
data = [row, col]
|
||||
chars = list(text)
|
||||
testarray = []
|
||||
for i in range(len(chars)):
|
||||
testarray.append(ord(chars[i]))
|
||||
data = data + testarray
|
||||
await self._send_sysex(BoardConstants.LCD_PRINT, data)
|
||||
|
||||
async def lcd_clear(self):
|
||||
"""
|
||||
:returns: No return value.
|
||||
"""
|
||||
data = []
|
||||
await self._send_sysex(BoardConstants.LCD_CLEAR, data)
|
||||
|
||||
async def dht_read(self, datapin):
|
||||
"""
|
||||
:param pin: pin number of the DHT11 data pin
|
||||
:returns: No return value.
|
||||
"""
|
||||
data = [datapin & 0x7F]
|
||||
self.dht_map[datapin] = [-1,-1,-1, 0, 0]
|
||||
await self._send_sysex(BoardConstants.DHT11_READ, data)
|
||||
|
||||
async def dht_data_retrieve(self, datapin):
|
||||
"""
|
||||
Retrieve DHT11 data. The data is presented as a
|
||||
dictionary.
|
||||
The 'key' is the data pin specified in dht11_config()
|
||||
and the 'data' is [status, temperature, humidity, temperatureDecimal, humidityDecimal ].
|
||||
|
||||
:param trigger_pin: key into sonar data map
|
||||
|
||||
:returns: dht_map
|
||||
"""
|
||||
dht_pin_entry = self.dht_map[datapin]
|
||||
|
||||
result = dht_pin_entry[0]
|
||||
|
||||
if(result == 255):
|
||||
dht_pin_entry[0] = 0
|
||||
if(result == 254):
|
||||
print("Checksum error")
|
||||
elif(result == 253):
|
||||
print("Timeout error")
|
||||
return dht_pin_entry
|
||||
|
||||
|
||||
async def _dht_data(self, data):
|
||||
data = data[1:-1]
|
||||
pin_number = data[0]
|
||||
result = data[1]
|
||||
if(result > 128):
|
||||
result -= 255
|
||||
dht_pin_entry = self.dht_map[pin_number]
|
||||
dht_pin_entry[0] = result
|
||||
dht_pin_entry[1] = data[2]
|
||||
dht_pin_entry[2] = data[4]
|
||||
dht_pin_entry[3] = data[3]
|
||||
dht_pin_entry[4] = data[5]
|
||||
self.dht_map[pin_number] = dht_pin_entry
|
||||
await asyncio.sleep(self.sleep_tune)
|
||||
|
||||
async def ping_read(self, triggerPin):
|
||||
"""
|
||||
:param triggerPin: pin number of the sonar trigger pin
|
||||
:returns: No return value.
|
||||
"""
|
||||
data = [triggerPin & 0x7F]
|
||||
self.ping_map[triggerPin] = -1
|
||||
await self._send_sysex(BoardConstants.PING_READ, data)
|
||||
|
||||
async def _ping_data(self, data):
|
||||
"""
|
||||
This method handles the incoming sonar data message and stores
|
||||
the data in the response table.
|
||||
|
||||
:param data: Message data from Firmata
|
||||
|
||||
:returns: No return value.
|
||||
"""
|
||||
|
||||
# strip off sysex start and end
|
||||
data = data[1:-1]
|
||||
pin_number = data[0]
|
||||
val = int((data[2] << 7) + data[1])
|
||||
#ping_pin_entry = self.ping_map[pin_number]
|
||||
#ping_pin_entry[1] = val
|
||||
self.ping_map[pin_number] = val
|
||||
await asyncio.sleep(self.sleep_tune)
|
||||
|
||||
async def ping_data_retrieve(self, datapin):
|
||||
"""
|
||||
Retrieve sonar data. The data is presented as a dictionary.
|
||||
The 'key' is the data pin specified in sonar_config()
|
||||
and the 'data' is [pin, distance].
|
||||
|
||||
:param trigger_pin: key into sonar data map
|
||||
|
||||
:returns: ping_map
|
||||
"""
|
||||
ping_pin_entry = self.ping_map[datapin]
|
||||
return ping_pin_entry
|
||||
749
code/.venv/lib/python3.12/site-packages/pyboard/pyboard_iot.py
Normal file
749
code/.venv/lib/python3.12/site-packages/pyboard/pyboard_iot.py
Normal file
@@ -0,0 +1,749 @@
|
||||
"""
|
||||
Copyright (c) 2018-2019 Kaiyu Liu, All rights reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3 as published by the Free Software Foundation; either
|
||||
or (at your option) any later version.
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
"""
|
||||
|
||||
|
||||
import asyncio
|
||||
import datetime
|
||||
import json
|
||||
import sys
|
||||
import signal
|
||||
import argparse
|
||||
import websockets
|
||||
from pymata_aio.constants import Constants
|
||||
from pyboard_core import PyBoardCore
|
||||
|
||||
|
||||
class PyboardIOT:
|
||||
def __init__(self, my_core):
|
||||
self.core = my_core
|
||||
|
||||
self.command_map = {
|
||||
"analogRead": self.analogRead,
|
||||
"analogWrite": self.analogWrite,
|
||||
"digitalRead": self.digitalRead,
|
||||
"digitalWrite": self.digitalWrite,
|
||||
"disableAnalogReporting": self.disableAnalogReporting,
|
||||
"disableDigitalReporting": self.disableDigitalReporting,
|
||||
"enableAnalogReporting": self.disableAnalogReporting,
|
||||
"enableDigitalReporting": self.disableDigitalReporting,
|
||||
"configEncoder": self.configEncoder,
|
||||
"encoderRead": self.encoderRead,
|
||||
"getAnalogLatchData": self.getAnalogLatchData,
|
||||
"getAnalogMap": self.getAnalogMap,
|
||||
"getCapabilityReport": self.getCapabilityReport,
|
||||
"getDigitalLatchData": self.getDigitalLatchData,
|
||||
"getFirmwareVersion": self.getFirmwareVersion,
|
||||
"getPinState": self.getPinState,
|
||||
"getProtocolVersion": self.getProtocolVersion,
|
||||
"get_pymata_version": self.get_pymata_version,
|
||||
"configI2C": self.configI2C,
|
||||
"readI2CData": self.readI2CData,
|
||||
"readI2CRequest": self.readI2CRequest,
|
||||
"writeI2CRequest": self.writeI2CRequest,
|
||||
"keepAlive": self.keepAlive,
|
||||
"configNeopixel": self.configNeopixel,
|
||||
"setNeopixelColor": self.setNeopixelColor,
|
||||
"playTone": self.playTone,
|
||||
"setAnalogLatch": self.setAnalogLatch,
|
||||
"setDigitalLatch": self.setDigitalLatch,
|
||||
"pinMode": self.pinMode,
|
||||
"setSamplingInterval": self.setSamplingInterval,
|
||||
"configSonar": self.configSonar,
|
||||
"sonar_read": self.sonar_read,
|
||||
"configServo": self.configServo,
|
||||
"configStepper": self.configStepper,
|
||||
"stepStepper": self.stepStepper
|
||||
}
|
||||
self.websocket = None
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
async def get_message(self, websocket, path):
|
||||
"""
|
||||
:param websocket: websocket
|
||||
:param path: path
|
||||
:return:
|
||||
"""
|
||||
|
||||
self.websocket = websocket
|
||||
try:
|
||||
while True:
|
||||
payload = await self.websocket.recv()
|
||||
|
||||
# cmd_dict = json.loads(payload.decode('utf8'))
|
||||
cmd_dict = json.loads(payload)
|
||||
client_cmd = cmd_dict.get("method")
|
||||
|
||||
if client_cmd in self.command_map:
|
||||
cmd = self.command_map.get(client_cmd)
|
||||
params = cmd_dict.get("params")
|
||||
if params[0] != "null":
|
||||
await cmd(params)
|
||||
else:
|
||||
await cmd()
|
||||
except websockets.exceptions.ConnectionClosed:
|
||||
sys.exit()
|
||||
|
||||
async def analogRead(self, command):
|
||||
"""
|
||||
This method reads and returns the last reported value for an analog pin.
|
||||
Normally not used since analog pin updates will be provided automatically
|
||||
as they occur with the analog_message_reply being sent to the client after pinMode is called.
|
||||
(see enableAnalogReporting for message format).
|
||||
|
||||
:param command: {"method": "analogRead", "params": [ANALOG_PIN]}
|
||||
:returns: {"method": "analogRead_reply", "params": [PIN, ANALOG_DATA_VALUE]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
data_val = await self.core.analog_read(pin)
|
||||
reply = json.dumps({"method": "analogRead_reply", "params": [pin, data_val]})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def analogWrite(self, command):
|
||||
"""
|
||||
This method writes a value to an analog pin.
|
||||
|
||||
It is used to set the output of a PWM pin or the angle of a Servo.
|
||||
|
||||
:param command: {"method": "analogWrite", "params": [PIN, WRITE_VALUE]}
|
||||
:returns: No return message.
|
||||
"""
|
||||
pin = int(command[0])
|
||||
value = int(command[1])
|
||||
await self.core.analog_write(pin, value)
|
||||
|
||||
async def digitalRead(self, command):
|
||||
"""
|
||||
This method reads and returns the last reported value for a digital pin.
|
||||
Normally not used since digital pin updates will be provided automatically
|
||||
as they occur with the digital_message_reply being sent to the client after pinMode is called..
|
||||
(see enableDigitalReporting for message format)
|
||||
|
||||
:param command: {"method": "digitalRead", "params": [PIN]}
|
||||
:returns: {"method": "digitalRead_reply", "params": [PIN, DIGITAL_DATA_VALUE]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
data_val = await self.core.digital_read(pin)
|
||||
reply = json.dumps({"method": "digitalRead_reply", "params": [pin, data_val]})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def digitalWrite(self, command):
|
||||
"""
|
||||
This method writes a zero or one to a digital pin.
|
||||
|
||||
:param command: {"method": "digitalWrite", "params": [PIN, DIGITAL_DATA_VALUE]}
|
||||
:returns: No return message..
|
||||
"""
|
||||
pin = int(command[0])
|
||||
value = int(command[1])
|
||||
await self.core.digital_write(pin, value)
|
||||
|
||||
async def disableAnalogReporting(self, command):
|
||||
"""
|
||||
Disable Firmata reporting for an analog pin.
|
||||
|
||||
:param command: {"method": "disableAnalogReporting", "params": [PIN]}
|
||||
:returns: No return message..
|
||||
"""
|
||||
pin = int(command[0])
|
||||
await self.core.disable_analog_reporting(pin)
|
||||
|
||||
async def disableDigitalReporting(self, command):
|
||||
"""
|
||||
Disable Firmata reporting for a digital pin.
|
||||
|
||||
:param command: {"method": "disableDigitalReporting", "params": [PIN]}
|
||||
:returns: No return message.
|
||||
"""
|
||||
pin = int(command[0])
|
||||
await self.core.disable_digital_reporting(pin)
|
||||
|
||||
async def enableAnalogReporting(self, command):
|
||||
"""
|
||||
Enable Firmata reporting for an analog pin.
|
||||
|
||||
:param command: {"method": "enableAnalogReporting", "params": [PIN]}
|
||||
:returns: {"method": "analog_message_reply", "params": [PIN, ANALOG_DATA_VALUE]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
await self.core.enable_analog_reporting(pin)
|
||||
|
||||
async def enableDigitalReporting(self, command):
|
||||
"""
|
||||
Enable Firmata reporting for a digital pin.
|
||||
|
||||
:param command: {"method": "enableDigitalReporting", "params": [PIN]}
|
||||
:returns: {"method": "digital_message_reply", "params": [PIN, DIGITAL_DATA_VALUE]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
await self.core.enable_digital_reporting(pin)
|
||||
|
||||
async def configEncoder(self, command):
|
||||
"""
|
||||
Configure 2 pins for FirmataPlus encoder operation.
|
||||
|
||||
:param command: {"method": "configEncoder", "params": [PIN_A, PIN_B]}
|
||||
:returns: {"method": "encoder_data_reply", "params": [ENCODER_DATA]}
|
||||
"""
|
||||
pin_a = int(command[0])
|
||||
pin_b = int(command[1])
|
||||
await self.core.encoder_config(pin_a, pin_b, self.encoder_callback)
|
||||
|
||||
async def encoderRead(self, command):
|
||||
"""
|
||||
This is a polling method to read the last cached FirmataPlus encoder value.
|
||||
Normally not used. See encoder config for the asynchronous report message format.
|
||||
|
||||
:param command: {"method": "encoderRead", "params": [PIN_A]}
|
||||
:returns: {"method": "encoderRead_reply", "params": [PIN_A, ENCODER_VALUE]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
val = await self.core.encoder_read(pin)
|
||||
reply = json.dumps({"method": "encoderRead_reply", "params": [pin, val]})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def getAnalogLatchData(self, command):
|
||||
"""
|
||||
This method retrieves a latch table entry for an analog pin.
|
||||
|
||||
See constants.py for definition of reply message parameters.
|
||||
|
||||
:param command: {"method": "getAnalogLatchData", "params": [ANALOG_PIN]}
|
||||
:returns: {"method": "getAnalogLatchData_reply", "params": [ANALOG_PIN, LATCHED_STATE, THRESHOLD_TYPE,\
|
||||
THRESHOLD_TARGET, DATA_VALUE, TIME_STAMP ]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
data_val = await self.core.get_analog_latch_data(pin)
|
||||
if data_val:
|
||||
data_val = data_val[0:-1]
|
||||
reply = json.dumps({"method": "getAnalogLatchData_reply", "params": [pin, data_val]})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def getAnalogMap(self):
|
||||
"""
|
||||
This method retrieves the Firmata analog map.
|
||||
|
||||
Refer to: http://firmata.org/wiki/Protocol#Analog_Mapping_Query to interpret the reply
|
||||
|
||||
The command JSON format is: {"method":"getAnalogMap","params":["null"]}
|
||||
:returns: {"method": "analog_map_reply", "params": [ANALOG_MAP]}
|
||||
"""
|
||||
value = await self.core.get_analog_map()
|
||||
if value:
|
||||
reply = json.dumps({"method": "analog_map_reply", "params": value})
|
||||
else:
|
||||
reply = json.dumps({"method": "analog_map_reply", "params": "None"})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def getCapabilityReport(self):
|
||||
"""
|
||||
This method retrieves the Firmata capability report.
|
||||
|
||||
Refer to http://firmata.org/wiki/Protocol#Capability_Query
|
||||
|
||||
The command format is: {"method":"getCapabilityReport","params":["null"]}
|
||||
|
||||
:returns: {"method": "capability_report_reply", "params": [RAW_CAPABILITY_REPORT]}
|
||||
"""
|
||||
value = await self.core.get_capability_report()
|
||||
await asyncio.sleep(.1)
|
||||
if value:
|
||||
reply = json.dumps({"method": "capability_report_reply", "params": value})
|
||||
else:
|
||||
reply = json.dumps({"method": "capability_report_reply", "params": "None"})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def getDigitalLatchData(self, command):
|
||||
"""
|
||||
This method retrieves a latch table entry for a digital pin.
|
||||
|
||||
See constants.py for definition of reply message parameters.
|
||||
|
||||
:param command: {"method": "getDigitalLatchData", "params": [DPIN]}
|
||||
:returns: {"method": "getDigitalLatchData_reply", "params": [DIGITAL_PIN, LATCHED_STATE, THRESHOLD_TYPE,\
|
||||
THRESHOLD_TARGET, DATA_VALUE, TIME_STAMP ]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
data_val = await self.core.get_digital_latch_data(pin)
|
||||
if data_val:
|
||||
data_val = data_val[0:-1]
|
||||
reply = json.dumps({"method": "getDigitalLatchData_reply", "params": [pin, data_val]})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def getFirmwareVersion(self):
|
||||
"""
|
||||
This method retrieves the Firmata firmware version.
|
||||
|
||||
See: http://firmata.org/wiki/Protocol#Query_Firmware_Name_and_Version
|
||||
|
||||
|
||||
JSON command: {"method": "getFirmwareVersion", "params": ["null"]}
|
||||
|
||||
:returns: {"method": "firmware_version_reply", "params": [FIRMWARE_VERSION]}
|
||||
"""
|
||||
value = await self.core.get_firmware_version()
|
||||
if value:
|
||||
reply = json.dumps({"method": "firmware_version_reply", "params": value})
|
||||
else:
|
||||
reply = json.dumps({"method": "firmware_version_reply", "params": "Unknown"})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def getPinState(self, command):
|
||||
"""
|
||||
This method retrieves a Firmata pin_state report for a pin..
|
||||
|
||||
See: http://firmata.org/wiki/Protocol#Pin_State_Query
|
||||
|
||||
:param command: {"method": "getPinState", "params": [PIN]}
|
||||
:returns: {"method": "getPinState_reply", "params": [PIN_NUMBER, PIN_MODE, PIN_STATE]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
value = await self.core.get_pin_state(pin)
|
||||
if value:
|
||||
reply = json.dumps({"method": "pin_state_reply", "params": value})
|
||||
else:
|
||||
reply = json.dumps({"method": "pin_state_reply", "params": "Unknown"})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def getProtocolVersion(self):
|
||||
"""
|
||||
This method retrieves the Firmata protocol version.
|
||||
|
||||
JSON command: {"method": "getProtocolVersion", "params": ["null"]}
|
||||
|
||||
:returns: {"method": "protocol_version_reply", "params": [PROTOCOL_VERSION]}
|
||||
"""
|
||||
value = await self.core.get_protocol_version()
|
||||
if value:
|
||||
reply = json.dumps({"method": "protocol_version_reply", "params": value})
|
||||
else:
|
||||
reply = json.dumps({"method": "protocol_version_reply", "params": "Unknown"})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def get_pymata_version(self):
|
||||
"""
|
||||
This method retrieves the PyMata release version number.
|
||||
|
||||
JSON command: {"method": "get_pymata_version", "params": ["null"]}
|
||||
|
||||
:returns: {"method": "pymata_version_reply", "params":[PYMATA_VERSION]}
|
||||
"""
|
||||
value = await self.core.get_pymata_version()
|
||||
if value:
|
||||
reply = json.dumps({"method": "pymata_version_reply", "params": value})
|
||||
else:
|
||||
reply = json.dumps({"method": "pymata_version_reply", "params": "Unknown"})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def configI2C(self, command):
|
||||
"""
|
||||
This method initializes the I2c and sets the optional read delay (in microseconds).
|
||||
|
||||
It must be called before doing any other i2c operations for a given device.
|
||||
:param command: {"method": "configI2C", "params": [DELAY]}
|
||||
:returns: No Return message.
|
||||
"""
|
||||
delay = int(command[0])
|
||||
await self.core.i2c_config(delay)
|
||||
|
||||
async def readI2CData(self, command):
|
||||
"""
|
||||
This method retrieves the last value read for an i2c device identified by address.
|
||||
This is a polling implementation and readI2CRequest and readI2CRequest_reply may be
|
||||
a better alternative.
|
||||
:param command: {"method": "readI2CData", "params": [I2C_ADDRESS ]}
|
||||
:returns:{"method": "readI2CData_reply", "params": i2c_data}
|
||||
"""
|
||||
address = int(command[0])
|
||||
i2c_data = await self.core.i2c_read_data(address)
|
||||
reply = json.dumps({"method": "readI2CData_reply", "params": i2c_data})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def readI2CRequest(self, command):
|
||||
"""
|
||||
This method sends an I2C read request to Firmata. It is qualified by a single shot, continuous
|
||||
read, or stop reading command.
|
||||
Special Note: for the read type supply one of the following string values:
|
||||
|
||||
"0" = I2C_READ
|
||||
|
||||
"1" = I2C_READ | I2C_END_TX_MASK"
|
||||
|
||||
"2" = I2C_READ_CONTINUOUSLY
|
||||
|
||||
"3" = I2C_READ_CONTINUOUSLY | I2C_END_TX_MASK
|
||||
|
||||
"4" = I2C_STOP_READING
|
||||
|
||||
:param command: {"method": "readI2CRequest", "params": [I2C_ADDRESS, I2C_REGISTER,
|
||||
NUMBER_OF_BYTES, I2C_READ_TYPE ]}
|
||||
:returns: {"method": "readI2CRequest_reply", "params": [DATA]}
|
||||
"""
|
||||
device_address = int(command[0])
|
||||
register = int(command[1])
|
||||
number_of_bytes = int(command[2])
|
||||
|
||||
if command[3] == "0":
|
||||
read_type = Constants.I2C_READ_CONTINUOUSLY
|
||||
elif command[3] == "1":
|
||||
read_type = Constants.I2C_READ
|
||||
elif command[3] == "2":
|
||||
read_type = Constants.I2C_READ | Constants.I2C_END_TX_MASK
|
||||
elif command[3] == "3":
|
||||
read_type = Constants.I2C_READ_CONTINUOUSLY | Constants.I2C_END_TX_MASK
|
||||
else: # the default case stop reading valid request or invalid request
|
||||
read_type = Constants.I2C_STOP_READING
|
||||
|
||||
await self.core.i2c_read_request(device_address, register, number_of_bytes, read_type,
|
||||
self.readI2CRequest_callback)
|
||||
await asyncio.sleep(.1)
|
||||
|
||||
async def writeI2CRequest(self, command):
|
||||
"""
|
||||
This method performs an I2C write at a given I2C address,
|
||||
:param command: {"method": "writeI2CRequest", "params": [I2C_DEVICE_ADDRESS, [DATA_TO_WRITE]]}
|
||||
:returns:No return message.
|
||||
"""
|
||||
device_address = int(command[0])
|
||||
params = command[1]
|
||||
params = [int(i) for i in params]
|
||||
await self.core.i2c_write_request(device_address, params)
|
||||
|
||||
async def keepAlive(self, command):
|
||||
"""
|
||||
Periodically send a keep alive message to the Arduino.
|
||||
Frequency of keep alive transmission is calculated as follows:
|
||||
keepAlive_sent = period - (period * margin)
|
||||
|
||||
:param command: {"method": "keepAlive", "params": [PERIOD, MARGIN]}
|
||||
Period is time period between keepalives. Range is 0-10 seconds. 0 disables the keepalive mechanism.
|
||||
Margin is a safety margin to assure keepalives are sent before period expires. Range is 0.1 to 0.9
|
||||
:returns: No return value
|
||||
"""
|
||||
period = int(command[0])
|
||||
margin = int(command[1])
|
||||
await self.core.keep_alive(period, margin)
|
||||
|
||||
async def playTone(self, command):
|
||||
"""
|
||||
This method controls a piezo device to play a tone. It is a FirmataPlus feature.
|
||||
Tone command is TONE_TONE to play, TONE_NO_TONE to stop playing.
|
||||
:param command: {"method": "playTone", "params": [PIN, TONE_COMMAND, FREQUENCY(Hz), DURATION(MS)]}
|
||||
:returns:No return message.
|
||||
"""
|
||||
pin = int(command[0])
|
||||
if command[1] == "TONE_TONE":
|
||||
tone_command = Constants.TONE_TONE
|
||||
else:
|
||||
tone_command = Constants.TONE_NO_TONE
|
||||
frequency = int(command[2])
|
||||
duration = int(command[3])
|
||||
await self.core.play_tone(pin, tone_command, frequency, duration)
|
||||
|
||||
async def setAnalogLatch(self, command):
|
||||
"""
|
||||
This method sets the an analog latch for a given analog pin, providing the threshold type, and
|
||||
latching threshold.
|
||||
:param command: {"method": "setAnalogLatch", "params": [PIN, THRESHOLD_TYPE, THRESHOLD_VALUE]}
|
||||
:returns:{"method": "analog_latch_data_reply", "params": [PIN, DATA_VALUE_LATCHED, TIMESTAMP_STRING]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
threshold_type = int(command[1])
|
||||
threshold_value = int(command[2])
|
||||
await self.core.set_analog_latch(pin, threshold_type, threshold_value, self.analog_latch_callback)
|
||||
|
||||
async def setDigitalLatch(self, command):
|
||||
"""
|
||||
This method sets the a digital latch for a given digital pin, the threshold type, and latching threshold.
|
||||
:param command:{"method": "setDigitalLatch", "params": [PIN, THRESHOLD (0 or 1)]}
|
||||
:returns:{"method": digital_latch_data_reply", "params": [PIN, DATA_VALUE_LATCHED, TIMESTAMP_STRING]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
threshold_value = int(command[1])
|
||||
await self.core.set_digital_latch(pin, threshold_value, self.digital_latch_callback)
|
||||
|
||||
async def pinMode(self, command):
|
||||
"""
|
||||
This method sets the pin mode for the selected pin. It handles: Input, Analog(Input) PWM, and OUTPUT. Servo
|
||||
is handled by configServo().
|
||||
:param command: {"method": "pinMode", "params": [PIN, MODE]}
|
||||
:returns:No return message.
|
||||
"""
|
||||
pin = int(command[0])
|
||||
mode = int(command[1])
|
||||
if mode == Constants.INPUT:
|
||||
cb = self.digital_callback
|
||||
elif mode == Constants.ANALOG:
|
||||
cb = self.analog_callback
|
||||
else:
|
||||
cb = None
|
||||
|
||||
await self.core.set_pin_mode(pin, mode, cb)
|
||||
|
||||
async def setSamplingInterval(self, command):
|
||||
"""
|
||||
This method sets the Firmata sampling interval in ms.
|
||||
:param command:{"method": "setSamplingInterval", "params": [INTERVAL]}
|
||||
:returns:No return message.
|
||||
"""
|
||||
sample_interval = int(command[0])
|
||||
await self.core.set_sampling_interval(sample_interval)
|
||||
|
||||
async def configSonar(self, command):
|
||||
"""
|
||||
This method configures 2 pins to support HC-SR04 Ping devices.
|
||||
This is a FirmataPlus feature.
|
||||
:param command: {"method": "configSonar", "params": [TRIGGER_PIN, ECHO_PIN, PING_INTERVAL(default=50),
|
||||
MAX_DISTANCE(default= 200 cm]}
|
||||
:returns:{"method": "sonar_data_reply", "params": [DISTANCE_IN_CM]}
|
||||
"""
|
||||
trigger = int(command[0])
|
||||
echo = int(command[1])
|
||||
interval = int(command[2])
|
||||
max_dist = int(command[3])
|
||||
await self.core.sonar_config(trigger, echo, self.sonar_callback, interval, max_dist)
|
||||
|
||||
async def sonar_read(self, command):
|
||||
"""
|
||||
This method retrieves the last sonar data value that was cached.
|
||||
This is a polling method. After sonar config, sonar_data_reply messages will be sent automatically.
|
||||
:param command: {"method": "sonar_read", "params": [TRIGGER_PIN]}
|
||||
:returns:{"method": "sonar_read_reply", "params": [TRIGGER_PIN, DATA_VALUE]}
|
||||
"""
|
||||
pin = int(command[0])
|
||||
val = await self.core.sonar_data_retrieve(pin)
|
||||
|
||||
reply = json.dumps({"method": "sonar_read_reply", "params": [pin, val]})
|
||||
await self.websocket.send(reply)
|
||||
|
||||
async def configNeopixel(self, command):
|
||||
"""
|
||||
This method configures a digital pin to support configNeopixel devices.
|
||||
This is a FirmataPlus feature.
|
||||
:param command: {"method": "configNeopixel", "params": [datapin,, count, brightness]}
|
||||
:returns:No message returned.
|
||||
"""
|
||||
pin = int(command[0])
|
||||
ledcount = int(command[1])
|
||||
brightness = int(command[2])
|
||||
await self.core.neopixel_config(pin, ledcount, brightness)
|
||||
|
||||
async def setNeopixelColor(self, command):
|
||||
"""
|
||||
This method retrieves the last sonar data value that was cached.
|
||||
This is a polling method. After sonar config, sonar_data_reply messages will be sent automatically.
|
||||
:param command: {"method": "sonar_read", "params": [TRIGGER_PIN]}
|
||||
:returns:{"method": "sonar_read_reply", "params": [TRIGGER_PIN, DATA_VALUE]}
|
||||
"""
|
||||
index = int(command[0])
|
||||
red = int(command[1])
|
||||
green = int(command[2])
|
||||
blue = int(command[3])
|
||||
await self.core.neopixel(index, red, green, blue)
|
||||
|
||||
|
||||
async def configServo(self, command):
|
||||
"""
|
||||
This method configures a pin for servo operation. The servo angle is set by using analogWrite().
|
||||
:param command: {"method": "configServo", "params": [PIN, MINIMUM_PULSE(ms), MAXIMUM_PULSE(ms)]}
|
||||
:returns:No message returned.
|
||||
"""
|
||||
pin = int(command[0])
|
||||
min_pulse = int(command[1])
|
||||
max_pulse = int(command[2])
|
||||
await self.core.servo_config(pin, min_pulse, max_pulse)
|
||||
|
||||
async def configStepper(self, command):
|
||||
"""
|
||||
This method configures 4 pins for stepper motor operation.
|
||||
This is a FirmataPlus feature.
|
||||
:param command: {"method": "configStepper", "params": [STEPS_PER_REVOLUTION, [PIN1, PIN2, PIN3, PIN4]]}
|
||||
:returns:No message returned.
|
||||
"""
|
||||
steps_per_revs = int(command[0])
|
||||
pins = command[1]
|
||||
pin1 = int(pins[0])
|
||||
pin2 = int(pins[1])
|
||||
pin3 = int(pins[2])
|
||||
pin4 = int(pins[3])
|
||||
await self.core.stepper_config(steps_per_revs, [pin1, pin2, pin3, pin4])
|
||||
|
||||
async def stepStepper(self, command):
|
||||
"""
|
||||
This method activates a stepper motor motion.
|
||||
This is a FirmataPlus feature.
|
||||
:param command: {"method": "stepper_step", "params": [SPEED, NUMBER_OF_STEPS]}
|
||||
:returns:No message returned.
|
||||
"""
|
||||
speed = int(command[0])
|
||||
num_steps = int(command[1])
|
||||
await self.core.stepper_step(speed, num_steps)
|
||||
|
||||
def analog_callback(self, data):
|
||||
"""
|
||||
This method handles the analog message received from pymata_core
|
||||
:param data: analog callback message
|
||||
:returns:{"method": "analog_message_reply", "params": [PIN, DATA_VALUE}
|
||||
"""
|
||||
reply = json.dumps({"method": "analog_message_reply", "params": [data[0], data[1]]})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
def analog_latch_callback(self, data):
|
||||
"""
|
||||
This method handles analog_latch data received from pymata_core
|
||||
:param data: analog latch callback message
|
||||
:returns:{"method": "analog_latch_data_reply", "params": [ANALOG_PIN, VALUE_AT_TRIGGER, TIME_STAMP_STRING]}
|
||||
"""
|
||||
ts = data[2]
|
||||
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
|
||||
reply = json.dumps({"method": "analog_latch_data_reply", "params": [data[0], data[1], st]})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
def digital_callback(self, data):
|
||||
"""
|
||||
This method handles the digital message received from pymata_core
|
||||
:param data: digital callback message
|
||||
:returns:{"method": "digital_message_reply", "params": [PIN, DATA_VALUE]}
|
||||
"""
|
||||
reply = json.dumps({"method": "digital_message_reply", "params": [data[0], data[1]]})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
def digital_latch_callback(self, data):
|
||||
"""
|
||||
This method handles the digital latch data message received from pymata_core
|
||||
:param data: digital latch callback message
|
||||
:returns:s{"method": "digital_latch_data_reply", "params": [PIN, DATA_VALUE_AT_TRIGGER, TIME_STAMP_STRING]}
|
||||
"""
|
||||
ts = data[2]
|
||||
st = datetime.datetime.fromtimestamp(ts).strftime('%Y-%m-%d %H:%M:%S')
|
||||
reply = json.dumps({"method": "digital_latch_data_reply", "params": [data[0], data[1], st]})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
def encoder_callback(self, data):
|
||||
"""
|
||||
This method handles the encoder data message received from pymata_core
|
||||
:param data: encoder data callback message
|
||||
:returns:{"method": "encoder_data_reply", "params": [ENCODER VALUE]}
|
||||
"""
|
||||
reply = json.dumps({"method": "encoder_data_reply", "params": data})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
def readI2CRequest_callback(self, data):
|
||||
"""
|
||||
This method handles the i2c read data message received from pymata_core.
|
||||
:param data: i2c read data callback message
|
||||
:returns:{"method": "readI2CRequest_reply", "params": [DATA_VALUE]}
|
||||
"""
|
||||
reply = json.dumps({"method": "readI2CRequest_reply", "params": data})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
def readI2CData_callback(self, data):
|
||||
"""
|
||||
This method handles the i2c cached read data received from pymata_core.
|
||||
:param data: i2c read cached data callback message
|
||||
:returns:{"method": "readI2CData_reply", "params": [DATA_VALUE]}
|
||||
"""
|
||||
reply = json.dumps({"method": "readI2CData_reply", "params": data})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
def sonar_callback(self, data):
|
||||
"""
|
||||
This method handles sonar data received from pymata_core.
|
||||
:param data: sonar data callback message
|
||||
:returns:{"method": "sonar_data_reply", "params": [DATA_VALUE]}
|
||||
"""
|
||||
reply = json.dumps({"method": "sonar_data_reply", "params": data})
|
||||
asyncio.ensure_future(self.websocket.send(reply))
|
||||
|
||||
|
||||
"""
|
||||
|
||||
usage: pymata_iot.py [-h] [-host HOSTNAME] [-port PORT] [-wait WAIT]
|
||||
[-comport COM] [-sleep SLEEP] [-log LOG]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-host HOSTNAME Server name or IP address
|
||||
-port PORT Server port number
|
||||
-wait WAIT Arduino wait time
|
||||
-comport COM Arduino COM port
|
||||
-sleep SLEEP sleep tune in ms.
|
||||
-log LOG True = send output to file, False = send output to console
|
||||
-ardIPAddr ADDR Wireless module ip address (WiFly)
|
||||
-ardPort PORT Wireless module ip port (Wifly)
|
||||
-handshake STR Wireless device handshake string (WiFly)
|
||||
"""
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-host", dest="hostname", default="localhost", help="Server name or IP address")
|
||||
parser.add_argument("-port", dest="port", default="9000", help="Server port number")
|
||||
parser.add_argument("-wait", dest="wait", default="2", help="Arduino wait time")
|
||||
parser.add_argument("-comport", dest="com", default="None", help="Arduino COM port")
|
||||
parser.add_argument("-sleep", dest="sleep", default=".001", help="sleep tune in ms.")
|
||||
parser.add_argument("-log", dest="log", default="False", help="redirect console output to log file")
|
||||
parser.add_argument("-ardIPAddr", dest="aIPaddr", default="None", help="Arduino IP Address (WiFly")
|
||||
parser.add_argument("-ardPort", dest="aIPport", default="2000", help="Arduino IP port (WiFly")
|
||||
parser.add_argument("-handshake", dest="handshake", default="*HELLO*", help="IP Device Handshake String")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
ip_addr = args.hostname
|
||||
ip_port = args.port
|
||||
|
||||
if args.com == 'None':
|
||||
comport = None
|
||||
else:
|
||||
comport = args.com
|
||||
|
||||
if args.log == 'True':
|
||||
log = True
|
||||
else:
|
||||
log = False
|
||||
|
||||
ard_ip_addr = args.aIPaddr
|
||||
ard_ip_port = args.aIPport
|
||||
ard_handshake = args.handshake
|
||||
|
||||
core = PyBoardCore(int(args.wait), float(args.sleep), log, comport,
|
||||
ard_ip_addr, ard_ip_port, ard_handshake)
|
||||
|
||||
# core = PymataCore()
|
||||
core.start()
|
||||
|
||||
|
||||
# Signal handler to trap control C
|
||||
# noinspection PyUnusedLocal,PyUnusedLocal
|
||||
def _signal_handler(sig, frame):
|
||||
if core is not None:
|
||||
print('\nYou pressed Ctrl+C')
|
||||
task = asyncio.ensure_future(core.shutdown())
|
||||
asyncio.get_event_loop().run_until_complete(task)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
signal.signal(signal.SIGINT, _signal_handler)
|
||||
signal.signal(signal.SIGTERM, _signal_handler)
|
||||
server = PyboardIOT(core)
|
||||
|
||||
try:
|
||||
start_server = websockets.serve(server.get_message, '127.0.0.1', 9000)
|
||||
|
||||
asyncio.get_event_loop().run_until_complete(start_server)
|
||||
|
||||
asyncio.get_event_loop().run_forever()
|
||||
except websockets.exceptions.ConnectionClosed:
|
||||
sys.exit()
|
||||
except RuntimeError:
|
||||
sys.exit()
|
||||
Reference in New Issue
Block a user