Skip to content

Commit 06e2402

Browse files
committed
feature/module: Add DualKmeter module 13.2
Signed-off-by: lbuque <[email protected]>
1 parent 7d61d4a commit 06e2402

File tree

5 files changed

+173
-0
lines changed

5 files changed

+173
-0
lines changed

m5stack/libs/module/__init__.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,20 @@
11
# -*- encoding: utf-8 -*-
2+
from . import mbus
3+
4+
_attrs = {
5+
"DualKmeter": "dual_kmeter",
6+
}
7+
8+
# Lazy loader, effectively does:
9+
# global attr
10+
# from .mod import attr
11+
# Filched from uasyncio.__init__.py
12+
13+
14+
def __getattr__(attr):
15+
mod = _attrs.get(attr, None)
16+
if mod is None:
17+
raise AttributeError(attr)
18+
value = getattr(__import__(mod, None, None, True, 1), attr)
19+
globals()[attr] = value
20+
return value

m5stack/libs/module/dual_kmeter.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
from .mbus import i2c1
2+
import struct
3+
4+
5+
_DUAL_KMETER_DEFAULT_ADDRESS = 0x11
6+
7+
_TEMP_CELSIUS_REG = const(0x00)
8+
_TEMP_FAHREN_REG = const(0x04)
9+
_TEMP_INT_CELSIUS_REG = const(0x10)
10+
_TEMP_INT_FAHREN_REG = const(0x14)
11+
_KMETER_SELECT_REG = const(0x20)
12+
_TEMP_READY_REG = const(0x30)
13+
_TEMP_STR_CELSIUS_REG = const(0x40)
14+
_TEMP_STR_FAHREN_REG = const(0x50)
15+
_TEMP_INTSTR_CELSIUS_REG = const(0x60)
16+
_FTEMP_INTSTR_FAHREN_REG = const(0x70)
17+
_FIRMWARE_VERSION_REG = const(0xFE)
18+
19+
20+
class DualKmeterBase:
21+
CELSIUS = const(0)
22+
FAHRENHEIT = const(1)
23+
24+
def __init__(self, i2c, address: int = _DUAL_KMETER_DEFAULT_ADDRESS):
25+
self._i2c = i2c
26+
self._addr = address
27+
28+
def get_thermocouple_temperature(self, scale=0) -> int:
29+
reg = _TEMP_CELSIUS_REG if scale == DualKmeter.CELSIUS else _TEMP_FAHREN_REG
30+
buff = self._i2c.readfrom_mem(self._addr, reg, 4)
31+
return round((self._int_convert(buff) / 100), 2)
32+
33+
def get_kmeter_temperature(self, scale=0) -> int:
34+
reg = _TEMP_INT_CELSIUS_REG if scale == DualKmeter.CELSIUS else _TEMP_INT_FAHREN_REG
35+
buff = self._i2c.readfrom_mem(self._addr, reg, 4)
36+
return round(self._int_convert(buff) / 100, 2)
37+
38+
def get_kmeter_channel(self) -> int:
39+
return self._i2c.readfrom_mem(self._addr, _KMETER_SELECT_REG, 1)[0]
40+
41+
def set_kmeter_channel(self, channel) -> None:
42+
channel = max(min(channel, 1), 0)
43+
return self._i2c.writeto_mem(self._addr, _KMETER_SELECT_REG, bytes([channel]))
44+
45+
def is_ready(self) -> bool:
46+
status = self._i2c.readfrom_mem(self._addr, _TEMP_READY_REG, 1)[0]
47+
return True if status == 0 else False
48+
49+
def get_thermocouple_temperature_string(self, scale=0):
50+
reg = _TEMP_STR_CELSIUS_REG if scale == DualKmeter.CELSIUS else _TEMP_STR_FAHREN_REG
51+
return "{:+.2f}".format(float(self._i2c.readfrom_mem(self._addr, reg, 8)))
52+
53+
def get_kmeter_temperature_string(self, scale=0):
54+
reg = _TEMP_INTSTR_CELSIUS_REG if scale == DualKmeter.CELSIUS else _FTEMP_INTSTR_FAHREN_REG
55+
return "{:+.2f}".format(float(self._i2c.readfrom_mem(self._addr, reg, 8)))
56+
57+
def get_fw_ver(self) -> int:
58+
return self._i2c.readfrom_mem(self._addr, _FIRMWARE_VERSION_REG, 1)[0]
59+
60+
def set_address(self, address: int) -> None:
61+
self._addr = address
62+
63+
def _int_convert(self, value) -> int:
64+
return struct.unpack("<i", value)[0]
65+
66+
67+
class DualKmeter(DualKmeterBase):
68+
def __init__(self, address: int = _DUAL_KMETER_DEFAULT_ADDRESS):
69+
super().__init__(i2c1, address)

m5stack/libs/module/mbus.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
from machine import I2C, Pin
2+
from M5 import getBoard, BOARD
3+
from collections import namedtuple
4+
5+
MBusIO = namedtuple("MBusIO", ["sda0", "scl0", "sda1", "scl1"])
6+
7+
iomap = {
8+
BOARD.M5StackCore2: MBusIO(32, 33, 21, 22),
9+
BOARD.M5StackCoreS3: MBusIO(2, 1, 12, 11),
10+
}.get(getBoard())
11+
12+
13+
def _i2c0_init():
14+
return I2C(1, scl=Pin(iomap.scl0), sda=Pin(iomap.sda0), freq=100000)
15+
16+
17+
def _i2c1_init():
18+
return I2C(1, scl=Pin(iomap.scl1), sda=Pin(iomap.sda1), freq=100000)
19+
20+
21+
_attrs = {
22+
"i2c0": _i2c0_init,
23+
"i2c1": _i2c1_init,
24+
}
25+
26+
27+
def __getattr__(attr):
28+
value = _attrs.get(attr, None)
29+
if value is None:
30+
raise AttributeError(attr)
31+
o = value()
32+
globals()[attr] = o
33+
return o

tests/module/dual_kmeter.m5f2

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"version":"V2.0","type":"cores3","components":[{"name":"screen","type":"screen","layer":0,"screenId":"builtin","screenName":"","id":"__cores3_screen","createTime":1692246482007,"x":0,"y":0,"width":280,"height":280,"backgroundColor":"#222222","size":0,"isSelected":true},{"name":"label0","type":"label","layer":1,"screenId":"builtin","screenName":"","id":"pLgX46ioxt30E=L4","createTime":1692246518609,"x":39,"y":41,"color":"#ffffff","backgroundColor":"#222222","text":"Text","engine":"gfx","font":"Widgets.FONTS.DejaVu18","rotation":0,"isSelected":false},{"name":"label1","type":"label","layer":2,"screenId":"builtin","screenName":"","id":"eAQcV5TAzhI3#JGF","createTime":1692252369529,"x":202,"y":57,"color":"#ffffff","backgroundColor":"#222222","text":"Text","engine":"gfx","font":"Widgets.FONTS.DejaVu18","rotation":0,"isSelected":false,"width":36,"height":20},{"name":"label2","type":"label","layer":3,"screenId":"builtin","screenName":"","id":"p6!3@HA+@Acc_A@f","createTime":1692252966532,"x":17,"y":139,"color":"#ffffff","backgroundColor":"#222222","text":"Text","engine":"gfx","font":"Widgets.FONTS.DejaVu18","rotation":0,"isSelected":false,"width":36,"height":20},{"name":"label3","type":"label","layer":4,"screenId":"builtin","screenName":"","id":"rmUt61F4JqFp74s3","createTime":1692252967813,"x":174,"y":146,"color":"#ffffff","backgroundColor":"#222222","text":"Text","engine":"gfx","font":"Widgets.FONTS.DejaVu18","rotation":0,"isSelected":false,"width":36,"height":20}],"resources":[{"module":["dualkmeter"]}],"units":[],"hats":[],"i2cs":[],"blockly":"<block type=\"basic_on_setup\" id=\"setup_block\" deletable=\"false\" x=\"50\" y=\"50\"><mutation isBegin=\"true\"></mutation><field name=\"UPDATEOP\">true</field><statement name=\"FUNC\"><block type=\"system_m5_begin\" id=\"system_m5_begin\"><next><block type=\"dualkmeter_init\" id=\"CSDu?dV]kv?Kn=X)qfuP\"><field name=\"NAME\">km_0</field><value name=\"ADDR\"><shadow type=\"math_number\" id=\"[z7PIf]d6p{G:J3_!l[6\"><mutation max=\"Infinity\" min=\"-Infinity\" precision=\"0\"></mutation><field name=\"NUM\">0x11</field></shadow></value><next><block type=\"dualkmeter_set_kmeter_channel\" id=\"VsbM~Acbu?Nqbe-:21rh\"><field name=\"NAME\">km_0</field><value name=\"CHANNEL\"><shadow type=\"dualkmeter_set_kmeter_channel_option\" id=\"6a..(/0pW]:7chr#JW/r\"><field name=\"VALUE\">0</field></shadow></value><next><block type=\"label_set_text\" id=\"H2dRd2L-,l+{Vdie4fiV\"><field name=\"NAME\">label0</field><value name=\"TEXT\"><shadow type=\"text\" id=\"NUu/%zEjGu_kr9J/=~`e\"><field name=\"TEXT\">Label</field></shadow><block type=\"dualkmeter_get_kmeter_channel\" id=\"G|zA#4P8E-/Mdh;|{X?7\"><field name=\"NAME\">km_0</field></block></value><next><block type=\"label_set_text\" id=\"-.:_iGyrk=@VcfnE1L#T\"><field name=\"NAME\">label0</field><value name=\"TEXT\"><shadow type=\"text\" id=\"+Wy%L1Abi-K+BL=RECmr\"><field name=\"TEXT\">Label</field></shadow><block type=\"dualkmeter_get_fw_ver\" id=\"j#)huI07R/Cp!Q|kKfvP\"><field name=\"NAME\">km_0</field></block></value></block></next></block></next></block></next></block></next></block></statement></block><block type=\"basic_on_loop\" id=\"loop_block\" deletable=\"false\" x=\"50\" y=\"370\"><mutation isUpdate=\"true\"></mutation><field name=\"UPDATEOP\">true</field><statement name=\"FUNC\"><block type=\"system_m5_update\" id=\"system_m5_update\"><next><block type=\"controls_if\" id=\"2w+|V9EZZV-$@YkTkgon\"><value name=\"IF0\"><block type=\"dualkmeter_is_ready\" id=\"*.Egz#o~Q;_,.u=YY,%,\"><field name=\"NAME\">km_0</field></block></value><statement name=\"DO0\"><block type=\"label_set_text\" id=\"=4Z,,G:5)L-$d?0*ISGz\"><field name=\"NAME\">label0</field><value name=\"TEXT\"><shadow type=\"text\" id=\"]819964sJ,K@/d]bqDtZ\"><field name=\"TEXT\">Label</field></shadow><block type=\"dualkmeter_get_thermocouple_temperature\" id=\"Yqz9F299?A[G-~Z/WdSb\"><field name=\"NAME\">km_0</field><field name=\"TYPE\">CELSIUS</field></block></value><next><block type=\"label_set_text\" id=\"cLUso.APs[j8Xf]IRDs]\"><field name=\"NAME\">label1</field><value name=\"TEXT\"><shadow type=\"text\" id=\"NUu/%zEjGu_kr9J/=~`e\"><field name=\"TEXT\">Label</field></shadow><block type=\"dualkmeter_get_thermocouple_temperature_string\" id=\"DKvX0p)6-s-+k{/v1lSI\"><field name=\"NAME\">km_0</field><field name=\"TYPE\">CELSIUS</field></block></value><next><block type=\"label_set_text\" id=\"(KU+v3XM#~,/CxP^1+[`\"><field name=\"NAME\">label2</field><value name=\"TEXT\"><shadow type=\"text\" id=\"63%7JRyjapzhy4qLwDrP\"><field name=\"TEXT\">Label</field></shadow><block type=\"dualkmeter_get_kmeter_temperature\" id=\"[/wvdh6)O-Z4Rt,B=Ana\"><field name=\"NAME\">km_0</field><field name=\"TYPE\">CELSIUS</field></block></value><next><block type=\"label_set_text\" id=\"U[MnK=dtpmw5#6)jzNW|\"><field name=\"NAME\">label3</field><value name=\"TEXT\"><shadow type=\"text\" id=\",v{EW)WF9+coEWb{uS-M\"><field name=\"TEXT\">Label</field></shadow><block type=\"dualkmeter_get_kmeter_temperature_string\" id=\"qa_5bwk3gLIi#8$oG7:u\"><field name=\"NAME\">km_0</field><field name=\"TYPE\">CELSIUS</field></block></value></block></next></block></next></block></next></block></statement></block></next></block></statement></block>","screen":[{"simulationName":"Built-in","type":"builtin","width":320,"height":240,"scale":0.78,"screenName":"","blockId":"","id":"builtin","createTime":1692246482004}]}

tests/module/dual_kmeter.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import os, sys, io
2+
import M5
3+
from M5 import *
4+
from module import DualKmeter
5+
6+
7+
label0 = None
8+
label1 = None
9+
label2 = None
10+
label3 = None
11+
km_0 = None
12+
13+
14+
def setup():
15+
global label0, label1, label2, label3, km_0
16+
17+
M5.begin()
18+
Widgets.fillScreen(0x222222)
19+
label0 = Widgets.Label("Text", 39, 41, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
20+
label1 = Widgets.Label("Text", 202, 57, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
21+
label2 = Widgets.Label("Text", 17, 139, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
22+
label3 = Widgets.Label("Text", 174, 146, 1.0, 0xFFFFFF, 0x222222, Widgets.FONTS.DejaVu18)
23+
24+
km_0 = DualKmeter(address=0x11)
25+
km_0.set_kmeter_channel(0)
26+
label0.setText(str(km_0.get_kmeter_channel()))
27+
label0.setText(str(km_0.get_fw_ver()))
28+
29+
30+
def loop():
31+
global label0, label1, label2, label3, km_0
32+
M5.update()
33+
if km_0.is_ready():
34+
label0.setText(str(km_0.get_thermocouple_temperature(scale=km_0.CELSIUS)))
35+
label1.setText(str(km_0.get_thermocouple_temperature_string(scale=km_0.CELSIUS)))
36+
label2.setText(str(km_0.get_kmeter_temperature(scale=km_0.CELSIUS)))
37+
label3.setText(str(km_0.get_kmeter_temperature_string(scale=km_0.CELSIUS)))
38+
39+
40+
if __name__ == "__main__":
41+
try:
42+
setup()
43+
while True:
44+
loop()
45+
except (Exception, KeyboardInterrupt) as e:
46+
try:
47+
from utility import print_error_msg
48+
49+
print_error_msg(e)
50+
except ImportError:
51+
print("please update to latest firmware")

0 commit comments

Comments
 (0)