Skip to content

Commit 4d39423

Browse files
authored
feat: add xl9535 support, issue #400 (#403)
* feat: add xl9535 support, issue #400
1 parent 4191b17 commit 4d39423

File tree

2 files changed

+83
-0
lines changed

2 files changed

+83
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ Hardware support is provided by specific GPIO, Sensor and Stream modules. It's e
2727
- PCF8575 IO expander (`pcf8575`)
2828
- PiFace Digital IO 2 (`piface2`)
2929
- Raspberry Pi GPIO (`raspberrypi`)
30+
- XL9535/PCA9535/TCA9535 IO expander (`xl9535`)
3031

3132
### Sensors
3233

mqtt_io/modules/gpio/xl9535.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
"""
2+
XL9535/PCA9535/TCA9535 IO expander
3+
"""
4+
5+
from typing import Optional, cast
6+
7+
from ...exceptions import RuntimeConfigError
8+
from ...types import ConfigType, PinType
9+
from . import GenericGPIO, PinDirection, PinPUD
10+
11+
REQUIREMENTS = ("smbus2",)
12+
CONFIG_SCHEMA = {
13+
"i2c_bus_num": {"type": "integer", "required": True, "empty": False},
14+
"chip_addr": {"type": "integer", "required": True, "empty": False},
15+
}
16+
17+
#XL9535_INPUT_PORT_0 = 0x00,
18+
#XL9535_INPUT_PORT_1 = 0x01
19+
XL9535_OUTPUT_PORT_0 = 0x02
20+
#XL9535_OUTPUT_PORT_1 = 0x03
21+
#XL9535_INVERSION_PORT_0 = 0x04
22+
#XL9535_INVERSION_PORT_1 = 0x05
23+
XL9535_CONFIG_PORT_0 = 0x06
24+
#XL9535_CONFIG_PORT_1 = 0x07
25+
26+
class GPIO(GenericGPIO):
27+
"""
28+
Implementation of GPIO class for the XL9535/PCA9535/TCA9535 IO expander chip.
29+
30+
Pin numbers 0 - 15.
31+
"""
32+
33+
PIN_SCHEMA = {
34+
"pin": {"type": 'integer', "required": True, "min": 0, "max": 15},
35+
}
36+
37+
def setup_module(self) -> None:
38+
# pylint: disable=import-outside-toplevel,import-error
39+
# pylint: disable=no-name-in-module
40+
from smbus2 import SMBus # type: ignore
41+
42+
self.bus = SMBus(self.config["i2c_bus_num"])
43+
self.address = self.config["chip_addr"]
44+
45+
# configure all pins as outputs
46+
self.bus.write_word_data(self.address, XL9535_CONFIG_PORT_0, 0x0000)
47+
# off all outputs be default
48+
self.bus.write_word_data(self.address, XL9535_OUTPUT_PORT_0, 0x0000)
49+
50+
def setup_pin(
51+
self,
52+
pin: PinType,
53+
direction: PinDirection,
54+
pullup: PinPUD,
55+
pin_config: ConfigType,
56+
initial: Optional[str] = None,
57+
) -> None:
58+
# I han't found any ready-made expansion boards on sale where the chip works as an input.
59+
# For simplicity, the implementation only supports the chip working in output mode.
60+
if direction == PinDirection.INPUT:
61+
raise RuntimeConfigError("Unsupported PinDirection: INPUT")
62+
initial = pin_config.get("initial")
63+
if initial is not None:
64+
if initial == "high":
65+
self.set_pin(pin, True)
66+
elif initial == "low":
67+
self.set_pin(pin, False)
68+
69+
def set_pin(self, pin: PinType, value: bool) -> None:
70+
assert pin in range(16), "Pin number must be an integer between 0 and 15"
71+
current_state = self.bus.read_word_data(self.address, XL9535_OUTPUT_PORT_0)
72+
bit = 1 << cast(int, pin)
73+
new_state = current_state | bit if value else current_state & (~bit & 0xffff)
74+
self.bus.write_word_data(self.address, XL9535_OUTPUT_PORT_0, new_state)
75+
76+
def get_pin(self, pin: PinType) -> bool:
77+
assert pin in range(16), "Pin number must be an integer between 0 and 15"
78+
state = self.bus.read_word_data(self.address, XL9535_OUTPUT_PORT_0)
79+
return bool(state & 1 << cast(int, pin))
80+
81+
def cleanup(self) -> None:
82+
self.bus.close()

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy