|
| 1 | +from machine import I2C |
| 2 | +from .pahub import PAHUBUnit |
| 3 | +from .unit_helper import UnitError |
| 4 | +import struct |
| 5 | +import sys |
| 6 | + |
| 7 | +if sys.platform != "esp32": |
| 8 | + from typing import Union |
| 9 | + |
| 10 | +import time |
| 11 | +import struct |
| 12 | + |
| 13 | +WEIGHT_I2C_ADDR = 0x26 |
| 14 | + |
| 15 | +ADC_REG = 0x00 |
| 16 | +WEIGHT_REG = 0x10 |
| 17 | +GAP_REG = 0x40 |
| 18 | +OFFSET_REG = 0x50 |
| 19 | +WEIGHT_X100_REG = 0x60 |
| 20 | +WEIGHT_STR_REG = 0x70 |
| 21 | +FILTER_IP_REG = 0x80 |
| 22 | +FILTER_AVG_REG = 0x81 |
| 23 | +FILTER_EMA_REG = 0x82 |
| 24 | +FW_VER_REG = 0xFE |
| 25 | +I2C_ADDR_REG = 0xFF |
| 26 | + |
| 27 | +class WEIGHT_I2CUnit: |
| 28 | + |
| 29 | + def __init__(self, i2c: Union[I2C, PAHUBUnit], addr=WEIGHT_I2C_ADDR) -> None: |
| 30 | + """Initialize the weight i2c sensor.""" |
| 31 | + self.i2c = i2c |
| 32 | + if addr >= 1 and addr <= 127: |
| 33 | + self.unit_addr = addr |
| 34 | + self._available() |
| 35 | + |
| 36 | + def _available(self) -> None: |
| 37 | + """! Check if sensor is available on the I2C bus.""" |
| 38 | + if not (self.unit_addr in self.i2c.scan()): |
| 39 | + raise UnitError("Weight Unit not found in Grove") |
| 40 | + |
| 41 | + @property |
| 42 | + def get_adc_raw(self) -> int: |
| 43 | + """! Get the ADC value.""" |
| 44 | + data = self.i2c.readfrom_mem(self.unit_addr, ADC_REG, 4) |
| 45 | + return struct.unpack('<I', data)[0] |
| 46 | + |
| 47 | + @property |
| 48 | + def get_weight_float(self) -> float: |
| 49 | + """! Get the weight in grams(float).""" |
| 50 | + data = self.i2c.readfrom_mem(self.unit_addr, WEIGHT_REG, 4) |
| 51 | + return round(struct.unpack('<f', data)[0], 3) |
| 52 | + |
| 53 | + def set_calibration(self, weight1_g: float, weight1_adc: int, weight2_g: float, weight2_adc: int) -> None: |
| 54 | + """! Calibration the Weight I2C sensor. |
| 55 | +
|
| 56 | + (1) step 1: Reset offset; |
| 57 | + (2) step 2: Get RawADC, this is RawADC_0g |
| 58 | + (3) step 3: Put 100g weight on it, and get RawADC, this is RawADC_100g |
| 59 | + (4) step 4: Calculate the value of GAP = (RawADC_100g-RawADC0g) / 100 |
| 60 | + (5) step 5: Write GAP value to the unit Via I2C |
| 61 | + |
| 62 | + weight1_g: Weight1 in grams. |
| 63 | + weight1_adc: Weight1 in ADC. |
| 64 | + weight2_g: Weight2 in grams. |
| 65 | + weight2_adc: Weight2 in ADC. |
| 66 | + """ |
| 67 | + |
| 68 | + gap = abs(weight2_adc - weight1_adc) / abs(weight2_g - weight1_g) |
| 69 | + self.i2c.writeto_mem(self.unit_addr, GAP_REG, struct.pack('<f', gap)) |
| 70 | + time.sleep_ms(200) |
| 71 | + |
| 72 | + def set_reset_offset(self) -> None: |
| 73 | + """! Reset offest weight value to zero.""" |
| 74 | + self.i2c.writeto_mem(self.unit_addr, OFFSET_REG, b'\x01') |
| 75 | + |
| 76 | + @property |
| 77 | + def get_weight_int(self) -> int: |
| 78 | + """! Get the weight in grams(int).""" |
| 79 | + data = self.i2c.readfrom_mem(self.unit_addr, WEIGHT_X100_REG, 4) |
| 80 | + return struct.unpack('<i', data)[0] |
| 81 | + |
| 82 | + @property |
| 83 | + def get_weight_str(self) -> str: |
| 84 | + """! Get the weight in grams(str).""" |
| 85 | + data = self.i2c.readfrom_mem(self.unit_addr, WEIGHT_STR_REG, 16) |
| 86 | + return data.replace(b'\x00', b'').decode('utf8') |
| 87 | + |
| 88 | + def set_lowpass_filter(self, enabled: bool) -> None: |
| 89 | + """! Set low pass filter enabled or not |
| 90 | + enabled: Enable or Disable |
| 91 | + """ |
| 92 | + self.i2c.writeto_mem(self.unit_addr, FILTER_IP_REG, bytes([enabled])) |
| 93 | + |
| 94 | + @property |
| 95 | + def get_lowpass_filter(self) -> bool: |
| 96 | + """! Get low pass filter enabled or not.""" |
| 97 | + return bool(self.i2c.readfrom_mem(self.unit_addr, FILTER_IP_REG, 1)[0]) |
| 98 | + |
| 99 | + def set_average_filter_level(self, level: int) -> None: |
| 100 | + """! Set average filter level |
| 101 | + level of average filter, larger value for smoother result but more latency |
| 102 | + level: 0~50 |
| 103 | + """ |
| 104 | + if level > 50 or level < 0: |
| 105 | + raise UnitError("Level for average filter must between 0 ~ 50") |
| 106 | + |
| 107 | + self.i2c.writeto_mem(self.unit_addr, FILTER_AVG_REG, struct.pack('b', level)) |
| 108 | + |
| 109 | + @property |
| 110 | + def get_average_filter_level(self) -> int: |
| 111 | + """! Get average filter level.""" |
| 112 | + return self.i2c.readfrom_mem(self.unit_addr, FILTER_AVG_REG, 1)[0] |
| 113 | + |
| 114 | + def set_ema_filter_alpha(self, alpha: int) -> None: |
| 115 | + """! Set ema filter alpha |
| 116 | + alpha of ema filter, smaller value for smoother result but more latency |
| 117 | + alpha: 0~99 |
| 118 | + """ |
| 119 | + if alpha > 99 or alpha < 0: |
| 120 | + raise Exception("Alpha for EMA filter must between 0 ~ 99") |
| 121 | + |
| 122 | + self.i2c.writeto_mem(self.unit_addr, FILTER_EMA_REG, struct.pack('b', alpha)) |
| 123 | + |
| 124 | + @property |
| 125 | + def get_ema_filter_alpha(self) -> int: |
| 126 | + """! Get ema filter alpha.""" |
| 127 | + return self.i2c.readfrom_mem(self.unit_addr, FILTER_EMA_REG, 1)[0] |
| 128 | + |
| 129 | + def get_device_spec(self, mode) -> int: |
| 130 | + """! Get device firmware version and i2c address. |
| 131 | + mode: 0xFE and 0xFF |
| 132 | + """ |
| 133 | + if mode >= FW_VER_REG and mode <= I2C_ADDR_REG: |
| 134 | + return self.i2c.readfrom_mem(self.unit_addr, mode, 1)[0] |
| 135 | + |
| 136 | + def set_i2c_address(self, addr) -> None: |
| 137 | + """! Set i2c address. |
| 138 | + addr: 1 to 127 |
| 139 | + """ |
| 140 | + if addr >= 1 and addr <= 127: |
| 141 | + if addr != self.unit_addr: |
| 142 | + self.i2c.writeto_mem(self.unit_addr, I2C_ADDR_REG, struct.pack('b', addr)) |
| 143 | + self.unit_addr = addr |
| 144 | + time.sleep_ms(200) |
| 145 | + |
0 commit comments