-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsparkfun_qwiicrelay.py
More file actions
executable file
·188 lines (151 loc) · 6.26 KB
/
sparkfun_qwiicrelay.py
File metadata and controls
executable file
·188 lines (151 loc) · 6.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# SPDX-FileCopyrightText: Copyright (c) 2021 Gaston Williams
#
# SPDX-License-Identifier: MIT
# The MIT License (MIT)
#
# Copyright (c) 2019 Gaston Williams for Sparkfun
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`sparkfun_qwiicrelay`
================================================================================
CircuitPython library for the Sparkfun Qwiic Relay
* Author(s): Gaston Williams
Implementation Notes
--------------------
**Hardware:**
* This is library is for the SparkFun Qwiic Single Relay.
* SparkFun sells these at its website: www.sparkfun.com
* Do you like this library? Help support SparkFun. Buy a board!
https://www.sparkfun.com/products/15093
**Software and Dependencies:**
* Adafruit CircuitPython firmware for the supported boards:
https://github.com/adafruit/circuitpython/releases
* Adafruit's Bus Device library: https://github.com/adafruit/Adafruit_CircuitPython_BusDevice
"""
# imports
# imports__version__ = "0.0.0-auto.0"
__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/fourstix/Sparkfun_CircuitPython_QwiicRelay.git"
from time import sleep
from micropython import const
from adafruit_bus_device.i2c_device import I2CDevice
# public constants
QWIIC_RELAY_ADDR = const(0x18) # default I2C Address
# private constants
_RELAY_OFF = const(0x00)
_RELAY_ON = const(0x01)
_RELAY_CHANGE_ADDRESS = const(0x03)
_RELAY_VERSION = const(0x04)
_RELAY_STATUS = const(0x05)
_RELAY_NOTHING_NEW = const(0x99)
# class
class Sparkfun_QwiicRelay:
"""CircuitPython class for the Sparkfun QwiicRelay"""
def __init__(self, i2c, address=QWIIC_RELAY_ADDR, debug=False):
"""Initialize Qwiic Relay for i2c communication."""
self._device = I2CDevice(i2c, address)
# save handle to i2c bus in case address is changed
self._i2c = i2c
self._debug = debug
# public properites
@property
def connected(self):
"""Check to see of the relay is available. Returns True if successful."""
# Attempt a connection and see if we get an error
try:
self._read_command(_RELAY_STATUS, 1)
except ValueError:
return False
return True
@property
def version(self):
"""Return the version string for the Relay firmware."""
# send command to get two bytes for the version string
version = self._read_command(_RELAY_VERSION, 2)
# Compute major and minor values from 16-bit version
minor = version[0] & 0xFF
major = version[1] & 0xFF
return "v" + str(major) + "." + str(minor)
@property
def status(self):
"""Return 1 if button pressed between reads. Button status is cleared."""
# read button status (since last check)
status = self._read_command(_RELAY_STATUS, 1)
return status[0] & 0xFF
@status.setter
def status(self, value):
"""Setting the status True turns relay on, False turns relay off."""
if bool(value):
self._write_command(_RELAY_ON)
else:
self._write_command(_RELAY_OFF)
# public functions
def relay_on(self):
"""Turn the relay on."""
self._write_command(_RELAY_ON)
def relay_off(self):
"""Turn the relay off."""
self._write_command(_RELAY_OFF)
def set_i2c_address(self, new_address):
"""Change the i2c address of Relay snd return True if successful."""
# check range of new address
if new_address < 8 or new_address > 119:
print("ERROR: Address outside 8-119 range")
return False
# write magic number 0x13 to lock register, to unlock address for update
# self._write_register(_RELAY_I2C_LOCK, 0x13)
# write new address
self._write_register(_RELAY_CHANGE_ADDRESS, new_address)
# wait a second for relay to settle after change
sleep(1)
# try to re-create new i2c device at new address
try:
self._device = I2CDevice(self._i2c, new_address)
except ValueError as err:
print("Address Change Failure")
print(err)
return False
# if we made it here, everything went fine
return True
# No i2c begin function is needed since I2Cdevice class takes care of that
# private functions
def _read_command(self, command, count):
# Send a command then read count number of bytes.
with self._device as device:
device.write(bytes([command]))
result = bytearray(count)
device.readinto(result)
# write_then_readinto function does not see to work
# device.write_then_readinto(bytes([command]), result)
if self._debug:
print("$%02X => %s" % (command, [hex(i) for i in result]))
return result
def _write_command(self, command):
# Send a byte command to the device
with self._device as device:
device.write(bytes([command & 0xFF]))
if self._debug:
print("$%02X" % (command))
def _write_register(self, addr, value):
# Write a byte to the specified 8-bit register address
with self._device as device:
device.write(bytes([addr & 0xFF, value & 0xFF]))
if self._debug:
print("$%02X <= 0x%02X" % (addr, value))