|
41 | 41 | * Adafruit CircuitPython firmware for the supported boards:
|
42 | 42 | https://github.com/adafruit/circuitpython/releases
|
43 | 43 |
|
44 |
| -.. todo:: Uncomment or remove the Bus Device and/or the Register library dependencies based on the library's use of either. |
45 |
| -
|
46 | 44 | # * Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
|
47 | 45 | # * Adafruit's Register library: https://github.com/adafruit/Adafruit_CircuitPython_Register
|
48 | 46 | """
|
|
51 | 49 |
|
52 | 50 | __version__ = "0.0.0-auto.0"
|
53 | 51 | __repo__ = "https://github.com/fourstix/Sparkfun_CircuitPython_QwiicRelay.git"
|
| 52 | + |
| 53 | +from time import sleep |
| 54 | +from micropython import const |
| 55 | +from adafruit_bus_device.i2c_device import I2CDevice |
| 56 | + |
| 57 | +# public constants |
| 58 | +QWIIC_RELAY_ADDR = const(0x18) #default I2C Address |
| 59 | + |
| 60 | +# private constants |
| 61 | +_RELAY_OFF = const(0x00) |
| 62 | +_RELAY_ON = const(0x01) |
| 63 | + |
| 64 | + |
| 65 | + |
| 66 | +_RELAY_CHANGE_ADDRESS = const(0x03) |
| 67 | +_RELAY_VERSION = const(0x04) |
| 68 | +_RELAY_STATUS = const(0x05) |
| 69 | +_RELAY_NOTHING_NEW = const(0x99) |
| 70 | + |
| 71 | +# class |
| 72 | +class Sparkfun_QwiicRelay: |
| 73 | + """CircuitPython class for the Sparkfun QwiicRelay""" |
| 74 | + |
| 75 | + def __init__(self, i2c, address=QWIIC_RELAY_ADDR, debug=False): |
| 76 | + """Initialize Qwiic Relay for i2c communication.""" |
| 77 | + self._device = I2CDevice(i2c, address) |
| 78 | + #save handle to i2c bus in case address is changed |
| 79 | + self._i2c = i2c |
| 80 | + self._debug = debug |
| 81 | + |
| 82 | +# public properites |
| 83 | + |
| 84 | + @property |
| 85 | + def connected(self): |
| 86 | + """Check to see of the relay is available. Returns True if successful.""" |
| 87 | + #Attempt a connection and see if we get an error |
| 88 | + try: |
| 89 | + with self._device as device: |
| 90 | + pass |
| 91 | + except ValueError: |
| 92 | + return False |
| 93 | + |
| 94 | + return True |
| 95 | + |
| 96 | + @property |
| 97 | + def version(self): |
| 98 | + """Return the version string for the Relay firmware.""" |
| 99 | + #send command to get two bytes for the version string |
| 100 | + version = self._command_read(_RELAY_VERSION, 2) |
| 101 | + # Compute major and minor values from 16-bit version |
| 102 | + minor = version[0] & 0xFF |
| 103 | + major = version[1] & 0xFF |
| 104 | + return 'v' + str(major) + '.' + str(minor) |
| 105 | + |
| 106 | + @property |
| 107 | + def status(self): |
| 108 | + """Return 1 if button pressed between reads. Button status is cleared.""" |
| 109 | + #read button status (since last check) |
| 110 | + status = self._command_read(_RELAY_STATUS, 1) |
| 111 | + |
| 112 | + return status[0] & 0xFF |
| 113 | + |
| 114 | + |
| 115 | +# public functions |
| 116 | + |
| 117 | + def on(self): |
| 118 | + """Turn the relay on.""" |
| 119 | + self._command_write(_RELAY_ON) |
| 120 | + |
| 121 | + |
| 122 | + def off(self): |
| 123 | + """Turn the relay off.""" |
| 124 | + self._command_write(_RELAY_OFF) |
| 125 | + |
| 126 | + def set_i2c_address(self, new_address): |
| 127 | + """Change the i2c address of Relay snd return True if successful.""" |
| 128 | + # check range of new address |
| 129 | + if (new_address < 8 or new_address > 119): |
| 130 | + print('ERROR: Address outside 8-119 range') |
| 131 | + return False |
| 132 | + # write magic number 0x13 to lock register, to unlock address for update |
| 133 | + # self._write_register(_RELAY_I2C_LOCK, 0x13) |
| 134 | + # write new address |
| 135 | + self._write_register(_RELAY_CHANGE_ADDRESS, new_address) |
| 136 | + |
| 137 | + # wait a second for relay to settle after change |
| 138 | + sleep(1) |
| 139 | + |
| 140 | + # try to re-create new i2c device at new address |
| 141 | + try: |
| 142 | + self._device = I2CDevice(self._i2c, new_address) |
| 143 | + except ValueError as err: |
| 144 | + print('Address Change Failure') |
| 145 | + print(err) |
| 146 | + return False |
| 147 | + |
| 148 | + #if we made it here, everything went fine |
| 149 | + return True |
| 150 | + |
| 151 | +# No i2c begin function is needed since I2Cdevice class takes care of that |
| 152 | + |
| 153 | +# private functions |
| 154 | + |
| 155 | + def _command_read(self, command, count): |
| 156 | + # Send a command then read count number of bytes. |
| 157 | + with self._device as device: |
| 158 | + device.write(bytes([command]), stop=False) |
| 159 | + result = bytearray(count) |
| 160 | + device.readinto(result) |
| 161 | + if self._debug: |
| 162 | + print("$%02X => %s" % (command, [hex(i) for i in result])) |
| 163 | + return result |
| 164 | + |
| 165 | + def _command_write(self, command): |
| 166 | + # Send a byte command to the device |
| 167 | + with self._device as device: |
| 168 | + device.write(bytes([command & 0xFF])) |
| 169 | + if self._debug: |
| 170 | + print("$%02X" % (command)) |
| 171 | + |
| 172 | + def _write_register(self, addr, value): |
| 173 | + # Write a byte to the specified 8-bit register address |
| 174 | + with self._device as device: |
| 175 | + device.write(bytes([addr & 0xFF, value & 0xFF])) |
| 176 | + if self._debug: |
| 177 | + print("$%02X <= 0x%02X" % (addr, value)) |
| 178 | + |
0 commit comments