Skip to content

Commit 145dc35

Browse files
committed
Add miniscale unit
1 parent 09001ee commit 145dc35

File tree

4 files changed

+247
-0
lines changed

4 files changed

+247
-0
lines changed

m5stack/libs/unit/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
"LoRaE220JPUnit": "lora_e220_jp",
4040
"WEIGHTUnit": "weight",
4141
"SCALESUnit": "scales",
42+
"MiniScale": "miniscale",
4243
}
4344

4445

m5stack/libs/unit/miniscale.py

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# -*- encoding: utf-8 -*-
2+
'''
3+
@File : _miniscale.py
4+
@Time : 2023/12/19
5+
@Author : TONG YIHAN
6+
7+
@License : (C)Copyright 2015-2023, M5STACK
8+
@Desc : This sensor is capable of measuring weight and also includes additional functionalities like LED control and various filters.
9+
'''
10+
11+
# Import necessary libraries
12+
from machine import I2C
13+
from .pahub import PAHUBUnit
14+
from .unit_helper import UnitError
15+
import time
16+
import struct
17+
try:
18+
from typing import Union
19+
except ImportError:
20+
pass
21+
22+
class Miniscale:
23+
"""! MiniScale is a weight sensor, includes a hx711 22bit ADC.
24+
25+
"""
26+
def __init__(self, i2c: Union[I2C, PAHUBUnit], addr=0x26):
27+
self.i2c = i2c
28+
self.addr = addr
29+
self._available()
30+
31+
def _available(self):
32+
"""! Check if sensor is available on the I2C bus.
33+
34+
Raises:
35+
UnitError: If the sensor is not found.
36+
"""
37+
if not (self.i2c_addr in self.i2c.scan()):
38+
raise UnitError("MiniScale Unit not found.")
39+
40+
@property
41+
def adc(self) -> int:
42+
"""! Get the ADC value."""
43+
data = self.i2c.readfrom_mem(self.addr, 0x00, 4)
44+
return struct.unpack('<I', data)[0]
45+
46+
@property
47+
def weight(self) -> float:
48+
"""! Get the weight in grams."""
49+
data = self.i2c.readfrom_mem(self.addr, 0x10, 4)
50+
return struct.unpack('<f', data)[0]
51+
52+
@property
53+
def button(self) -> bool:
54+
"""! Get the button state."""
55+
data = self.i2c.readfrom_mem(self.addr, 0x20, 1)
56+
return struct.unpack('b', data)[0] == 0
57+
58+
def setLed(self, r: int, g: int, b: int):
59+
"""! Set the RGB LED color.
60+
61+
@param r Red value. 0 - 255
62+
@param g Green value. 0 - 255
63+
@param b Blue value. 0 - 255
64+
"""
65+
self.i2c.writeto_mem(self.addr, 0x30, bytes([r, g, b]))
66+
67+
def reset(self):
68+
"""! Reset weight value to zero
69+
70+
"""
71+
self.i2c.writeto_mem(self.addr, 0x50, b'\x01')
72+
73+
def calibration(self, weight1_g: float, weight1_adc: int, weight2_g: float, weight2_adc: int):
74+
"""! Calibration the MiniScale sensor.
75+
76+
(1) step 1: Reset offset;
77+
(2) step 2: Get RawADC, this is RawADC_0g
78+
(3) step 3: Put 100g weight on it, and get RawADC, this is RawADC_100g
79+
(4) step 4: Calculate the value of GAP = (RawADC_100g-RawADC0g) / 100
80+
(5) step 5: Write GAP value to the unit Via I2C
81+
82+
@param weight1_g Weight1 in grams.
83+
@param weight1_adc Weight1 in ADC.
84+
@param weight2_g Weight2 in grams.
85+
@param weight2_adc Weight2 in ADC.
86+
"""
87+
88+
gap = (weight2_adc - weight1_adc) / (weight2_g - weight1_g)
89+
self.i2c.writeto_mem(self.addr, 0x40, struct.pack('<f', gap))
90+
91+
def setLowPassFilter(self, enabled: bool):
92+
"""! Set low pass filter enabled or not
93+
94+
@param enabled Enable filter or not
95+
"""
96+
if enabled:
97+
self.i2c.writeto_mem(self.addr, 0x80, b'\x01')
98+
else:
99+
self.i2c.writeto_mem(self.addr, 0x80, b'\x00')
100+
101+
def getLowPassFilter(self) -> bool:
102+
"""! Get low pass filter enabled or not
103+
104+
"""
105+
data = self.i2c.readfrom_mem(self.addr, 0x80, 1)
106+
return data == b'\x01'
107+
108+
def setAverageFilterLevel(self, level: int):
109+
"""! Set average filter level
110+
111+
@param level level of average filter, larger value for smoother result but more latency
112+
"""
113+
if level > 50 or level < 0:
114+
raise Exception("Level for average filter must between 0 ~ 50")
115+
116+
self.i2c.writeto_mem(self.addr, 0x81, struct.pack('b', level))
117+
118+
def getAverageFilterLevel(self) -> int:
119+
"""! Get average filter level
120+
121+
"""
122+
data = self.i2c.readfrom_mem(self.addr, 0x81, 1)
123+
return struct.unpack('b', data)[0]
124+
125+
def setEMAFilterAlpha(self, alpha: int):
126+
"""! Set ema filter alpha
127+
128+
@param alpha alpha of ema filter, smaller value for smoother result but more latency
129+
"""
130+
if alpha > 99 or alpha < 0:
131+
raise Exception("Alpha for EMA filter must between 0 ~ 99")
132+
133+
self.i2c.writeto_mem(self.addr, 0x82, struct.pack('b', alpha))
134+
135+
def getEMAFilterAlpha(self) -> int:
136+
"""! Get ema filter alpha
137+
138+
"""
139+
data = self.i2c.readfrom_mem(self.addr, 0x82, 1)
140+
return struct.unpack('b', data)[0]

m5stack/test/test.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import os, sys, io
2+
import M5
3+
from M5 import *
4+
from unit import *
5+
6+
label0 = None
7+
label1 = None
8+
lorae220_0 = None
9+
10+
11+
lorae220_rssi = None
12+
lorae220_data = None
13+
14+
15+
def lorae220_0_receive_event(received_data, rssi):
16+
global label0, label1, lorae220_0, lorae220_rssi, lorae220_data
17+
_ = received_data
18+
lorae220_rssi = rssi
19+
print(received_data)
20+
label0.setText(received_data.decode('ascii'))
21+
22+
23+
def setup():
24+
global label0, label1, lorae220_0, lorae220_rssi, lorae220_data
25+
26+
lorae220_0 = LoRaE220JPUnit((33, 32))
27+
M5.begin()
28+
Widgets.fillScreen(0x222222)
29+
label0 = Widgets.Label("label0", 37, 43, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
30+
label1 = Widgets.Label("label1", 37, 130, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
31+
32+
lorae220_0.setup(0x0000, 0, 0x2333)
33+
lorae220_0.receiveNoneBlock(lorae220_0_receive_event)
34+
35+
36+
def loop():
37+
global label0, label1, lorae220_0, lorae220_rssi, lorae220_data
38+
M5.update()
39+
lorae220_0.send(0x0000, 0, 'Hello???')
40+
41+
42+
if __name__ == '__main__':
43+
try:
44+
setup()
45+
while True:
46+
loop()
47+
except (Exception, KeyboardInterrupt) as e:
48+
try:
49+
from utility import print_error_msg
50+
print_error_msg(e)
51+
except ImportError:
52+
print("please update to latest firmware")

m5stack/test/test2.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
import os, sys, io
2+
import M5
3+
from M5 import *
4+
import time
5+
from unit import *
6+
7+
8+
label0 = None
9+
label1 = None
10+
lorae220_0 = None
11+
12+
13+
lorae220_rssi = None
14+
lorae220_data = None
15+
16+
17+
def lorae220_0_receive_event(received_data, rssi):
18+
global label0, label1, lorae220_0, lorae220_rssi, lorae220_data
19+
lorae220_data = received_data
20+
lorae220_rssi = rssi
21+
label0.setText(str(lorae220_data.decode()))
22+
23+
24+
def setup():
25+
global label0, label1, lorae220_0, lorae220_rssi, lorae220_data
26+
27+
lorae220_0 = LoRaE220JPUnit((33, 32))
28+
M5.begin()
29+
Widgets.fillScreen(0x222222)
30+
label0 = Widgets.Label("label0", 37, 43, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
31+
label1 = Widgets.Label("label1", 37, 130, 1.0, 0xffffff, 0x222222, Widgets.FONTS.DejaVu18)
32+
33+
lorae220_0.setup(0x0000, 0, 0x2333)
34+
lorae220_0.receiveNoneBlock(lorae220_0_receive_event)
35+
36+
37+
def loop():
38+
global label0, label1, lorae220_0, lorae220_rssi, lorae220_data
39+
M5.update()
40+
lorae220_0.send(0x0000, 0, 'Hello???555')
41+
time.sleep(2)
42+
43+
44+
if __name__ == '__main__':
45+
try:
46+
setup()
47+
while True:
48+
loop()
49+
except (Exception, KeyboardInterrupt) as e:
50+
try:
51+
from utility import print_error_msg
52+
print_error_msg(e)
53+
except ImportError:
54+
print("please update to latest firmware")

0 commit comments

Comments
 (0)