Skip to content

Fix long press not detected when on-press handler is absent #7

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Oct 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@ To use this library you can import the `modulino` module along with the desired
from modulino import ModulinoPixels

pixels = ModulinoPixels()

if not pixels.connected:
print("🤷 No pixel modulino found")
exit()
```
Once the desired object is obtained you can call functions and query properties on these objects such as `pixels.set_all_rgb(255, 0, 0)`.

Expand Down
5 changes: 0 additions & 5 deletions examples/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,9 @@
"""

from modulino import ModulinoButtons
from sys import exit

buttons = ModulinoButtons()

if not buttons.connected:
print("🤷 No button modulino found")
exit()

buttons.on_button_a_press = lambda : print("Button A pressed")
buttons.on_button_a_long_press = lambda : print("Button A long press")
buttons.on_button_a_release = lambda : print("Button A released")
Expand Down
47 changes: 47 additions & 0 deletions examples/change_address.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
"""
This example shows how to change the I2C address of a Modulino device.
After changing the address, the device will be reset and the new address will be verified.
From then on, when creating a Modulino object, you should use the new address.
e.g. ModulinoBuzzer(address=0x2A)

Initial author: Sebastian Romero ([email protected])
"""

from sys import exit
from time import sleep
from modulino import Modulino

print()
devices = Modulino.available_devices()

if len(devices) == 0:
print("No devices found on the bus. Try resetting the board.")
exit(1)

print("The following devices were found on the bus:")

for index, device in enumerate(devices):
print(f"{index + 1}) {device.device_type} at {hex(device.address)}")

choice = int(input("\nEnter the device number for which you want to change the address: "))

if choice < 1 or choice > len(devices):
print("Invalid choice. Please select a valid device number.")
exit(1)

selected_device = devices[choice - 1]
new_address = int(input("Enter the new address (hexadecimal or decimal): "), 0)

if new_address < 0 or new_address > 127:
print("Invalid address. Address must be between 0 and 127")
exit(1)

print(f"Changing address of device at {hex(selected_device.address)} to {hex(new_address)}...")
selected_device.change_address(new_address)
sleep(1) # Give the device time to reset

# Check if the address was successfully changed
if selected_device.connected:
print(f"✅ Address changed successfully to {hex(new_address)}")
else:
print("❌ Failed to change address. Please try again.")
5 changes: 0 additions & 5 deletions examples/pixels.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,9 @@

from modulino import ModulinoPixels, ModulinoColor
from time import sleep
from sys import exit

pixels = ModulinoPixels()

if not pixels.connected:
print("🤷 No pixel modulino found")
exit()

for index in range(0, 8):
color_wheel_colors = [
(255, 0, 0),
Expand Down
5 changes: 0 additions & 5 deletions examples/thermo.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@

from modulino import ModulinoThermo
from time import sleep
from sys import exit

thermo_module = ModulinoThermo()

if not thermo_module.connected:
print("🤷 No thermo modulino found")
exit()

while True:
temperature = thermo_module.temperature
humidity = thermo_module.relative_humidity
Expand Down
15 changes: 9 additions & 6 deletions src/modulino/buttons.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,21 +144,24 @@ def update(self):
# Check for press and release
if(button_states_changed):

if(new_status[0] == 1 and previous_status[0] == 0 and self._on_button_a_press):
if(new_status[0] == 1 and previous_status[0] == 0):
self._last_press_timestamps[0] = ticks_ms()
self._on_button_a_press()
if(self._on_button_a_press):
self._on_button_a_press()
elif(new_status[0] == 0 and previous_status[0] == 1 and self._on_button_a_release):
self._on_button_a_release()

if(new_status[1] == 1 and previous_status[1] == 0 and self._on_button_b_press):
if(new_status[1] == 1 and previous_status[1] == 0):
self._last_press_timestamps[1] = ticks_ms()
self._on_button_b_press()
if(self._on_button_b_press):
self._on_button_b_press()
elif(new_status[1] == 0 and previous_status[1] == 1 and self._on_button_b_release):
self._on_button_b_release()

if(new_status[2] == 1 and previous_status[2] == 0 and self._on_button_c_press):
if(new_status[2] == 1 and previous_status[2] == 0):
self._last_press_timestamps[2] = ticks_ms()
self._on_button_c_press()
if(self._on_button_c_press):
self._on_button_c_press()
elif(new_status[2] == 0 and previous_status[2] == 1 and self._on_button_c_release):
self._on_button_c_release()

Expand Down
46 changes: 46 additions & 0 deletions src/modulino/modulino.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,14 @@
"Generic ESP32S3 module" : I2CInterface("hw", 0, None, None),
}

PINSTRAP_ADDRESS_MAP = {
0x3C: "Buzzer",
0x7C: "Buttons",
0x76: "Knob",
0x74: "Knob",
0x6C: "Pixels"
}

class I2CHelper:
"""
A helper class for interacting with I2C devices on supported boards.
Expand Down Expand Up @@ -174,6 +182,31 @@ def pin_strap_address(self):
# The first byte is always the pinstrap address
return data[0]

@property
def device_type(self):
"""
Returns the type of the modulino based on the pinstrap address.
"""
return PINSTRAP_ADDRESS_MAP.get(self.pin_strap_address, None)

def change_address(self, new_address):
"""
Sets the address of the i2c device to the given value.
"""
# TODO: Check if device supports this feature by looking at the type

data = bytearray(40)
# Set the first two bytes to 'C' and 'F' followed by the new address
data[0:2] = b'CF'
data[2] = new_address * 2

try:
self.write(data)
except OSError:
pass # Device resets immediately and causes ENODEV to be thrown which is expected

self.address = new_address

def read(self, amount_of_bytes):
"""
Reads the given amount of bytes from the i2c device and returns the data.
Expand Down Expand Up @@ -207,6 +240,19 @@ def has_default_address(self):
"""
return self.address in self.default_addresses

@staticmethod
def available_devices():
"""
Finds all devices on the i2c bus and returns a list of Modulino objects.
"""
bus = I2CHelper.get_interface()
device_addresses = bus.scan()
devices = []
for address in device_addresses:
device = Modulino(i2c_bus=bus, address=address)
devices.append(device)
return devices

@staticmethod
def reset_bus(i2c_bus):
"""
Expand Down