Skip to content
GitLab
Explore
Sign in
Register
Primary navigation
Search or go to…
Project
flow3r firmware
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
dos
flow3r firmware
Commits
81c2eddc
Commit
81c2eddc
authored
Oct 4, 2023
by
Timon
Browse files
Options
Downloads
Patches
Plain Diff
More accurate battery tracking and no-battery detection
parent
cdc0f70e
No related branches found
No related tags found
No related merge requests found
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
python_payload/st3m/power.py
+180
-32
180 additions, 32 deletions
python_payload/st3m/power.py
python_payload/st3m/ui/elements/overlays.py
+40
-24
40 additions, 24 deletions
python_payload/st3m/ui/elements/overlays.py
sim/fakes/machine.py
+4
-1
4 additions, 1 deletion
sim/fakes/machine.py
with
224 additions
and
57 deletions
python_payload/st3m/power.py
+
180
−
32
View file @
81c2eddc
import
machine
import
machine
import
time
import
time
import
sys_kernel
import
sys_kernel
from
st3m
import
logging
log
=
logging
.
Log
(
__name__
,
level
=
logging
.
DEBUG
)
class
Power
:
class
Power
:
...
@@ -11,9 +14,25 @@ class Power:
...
@@ -11,9 +14,25 @@ class Power:
"""
"""
def
__init__
(
self
)
->
None
:
def
__init__
(
self
)
->
None
:
self
.
_adc_pin
=
machine
.
Pin
(
9
,
machine
.
Pin
.
IN
)
self
.
_adc_pin
=
machine
.
Pin
(
9
,
machine
.
Pin
.
IN
,
pull
=
None
)
# with no battery will be pulled down from the voltage divider
# current too low with 1M for ADC so need to check via GPIO
bat_read
=
0
for
i
in
range
(
5
):
time
.
sleep
(
0.002
)
bat_read
+=
self
.
_adc_pin
.
value
()
if
bat_read
>
4
:
self
.
_has_battery
=
True
else
:
self
.
_has_battery
=
False
self
.
_adc
=
machine
.
ADC
(
self
.
_adc_pin
,
atten
=
machine
.
ADC
.
ATTN_11DB
)
self
.
_adc
=
machine
.
ADC
(
self
.
_adc_pin
,
atten
=
machine
.
ADC
.
ATTN_11DB
)
self
.
_battery_voltage
=
self
.
_battery_voltage_sample
()
self
.
_battery_voltage
=
self
.
_battery_voltage_sample
()
self
.
_prev_battery_percentages
=
[
1
,
1
,
1
]
self
.
_battery_percentage
=
1
# speeding up the process to get an intial settled value because recursion is hard
for
i
in
range
(
5
):
self
.
_approximate_battery_percentage
()
self
.
_ts
=
time
.
ticks_ms
()
self
.
_ts
=
time
.
ticks_ms
()
def
_battery_voltage_sample
(
self
)
->
float
:
def
_battery_voltage_sample
(
self
)
->
float
:
...
@@ -21,9 +40,12 @@ class Power:
...
@@ -21,9 +40,12 @@ class Power:
def
_update
(
self
)
->
None
:
def
_update
(
self
)
->
None
:
ts
=
time
.
ticks_ms
()
ts
=
time
.
ticks_ms
()
if
t
s
>=
self
.
_ts
+
1
000
:
if
t
ime
.
ticks_diff
(
ts
,
self
.
_ts
)
>
2
000
:
# Sampling takes time, don't do it too often
# Sampling takes time, don't do it too often
log
.
debug
(
"
has battery:
"
+
str
(
self
.
_has_battery
))
log
.
debug
(
"
is charging:
"
+
str
(
self
.
battery_charging
))
self
.
_battery_voltage
=
self
.
_battery_voltage_sample
()
self
.
_battery_voltage
=
self
.
_battery_voltage_sample
()
self
.
_battery_percentage
=
self
.
_approximate_battery_percentage
()
self
.
_ts
=
ts
self
.
_ts
=
ts
@property
@property
...
@@ -31,6 +53,10 @@ class Power:
...
@@ -31,6 +53,10 @@ class Power:
self
.
_update
()
self
.
_update
()
return
self
.
_battery_voltage
return
self
.
_battery_voltage
@property
def
has_battery
(
self
)
->
bool
:
return
self
.
_has_battery
@property
@property
def
battery_charging
(
self
)
->
bool
:
def
battery_charging
(
self
)
->
bool
:
"""
"""
...
@@ -38,34 +64,156 @@ class Power:
...
@@ -38,34 +64,156 @@ class Power:
"""
"""
return
sys_kernel
.
battery_charging
()
return
sys_kernel
.
battery_charging
()
@property
def
battery_percentage
(
self
)
->
int
:
self
.
_update
()
return
self
.
_battery_percentage
def
approximate_battery_percentage
(
voltage
:
float
)
->
floa
t
:
def
_
approximate_battery_percentage
(
self
)
->
in
t
:
"""
"""
Returns approximate battery percentage ([0,100]) based on battery voltage
Returns approximate battery percentage ([0,100]) based on battery voltage.
(in volts).
"""
"""
if
voltage
>
4.20
:
if
not
self
.
_has_battery
:
return
100
return
100
piecewise
=
[
(
100
,
4.20
),
percentage
=
0
(
90
,
4.06
),
num_samples
=
10
(
80
,
3.98
),
voltage_readings
=
[]
(
70
,
3.92
),
for
i
in
range
(
num_samples
):
(
60
,
3.87
),
voltage_readings
.
append
(
self
.
_battery_voltage_sample
())
(
50
,
3.82
),
(
40
,
3.79
),
voltage_readings
.
sort
()
(
30
,
3.77
),
voltage
=
voltage_readings
[
int
(
num_samples
/
2
)]
(
20
,
3.74
),
(
10
,
3.68
),
# print(voltage)
(
5
,
3.45
),
(
0
,
3.00
),
if
voltage
>
4.120
:
percentage
=
100
# LUT created from Joulescope measurement of "official" 2Ah Battery at 650mW discharge at 26°C and decimated from ~42k samples
batLUT
=
[
(
99
,
4.114
),
(
98
,
4.109
),
(
97
,
4.091
),
(
96
,
4.076
),
(
95
,
4.061
),
(
94
,
4.048
),
(
93
,
4.036
),
(
92
,
4.024
),
(
91
,
4.012
),
(
90
,
4.001
),
(
89
,
3.989
),
(
88
,
3.978
),
(
87
,
3.967
),
(
86
,
3.956
),
(
85
,
3.945
),
(
84
,
3.934
),
(
83
,
3.923
),
(
82
,
3.912
),
(
81
,
3.901
),
(
80
,
3.890
),
(
79
,
3.879
),
(
78
,
3.869
),
(
77
,
3.858
),
(
76
,
3.847
),
(
75
,
3.837
),
(
74
,
3.827
),
(
73
,
3.817
),
(
72
,
3.807
),
(
71
,
3.797
),
(
70
,
3.788
),
(
69
,
3.778
),
(
67
,
3.769
),
(
66
,
3.759
),
(
65
,
3.750
),
(
64
,
3.741
),
(
63
,
3.732
),
(
62
,
3.723
),
(
61
,
3.715
),
(
60
,
3.706
),
(
59
,
3.698
),
(
58
,
3.690
),
(
57
,
3.682
),
(
56
,
3.674
),
(
55
,
3.666
),
(
54
,
3.659
),
(
53
,
3.652
),
(
52
,
3.645
),
(
51
,
3.639
),
(
50
,
3.633
),
(
49
,
3.627
),
(
48
,
3.622
),
(
47
,
3.617
),
(
46
,
3.609
),
(
45
,
3.605
),
(
44
,
3.602
),
(
43
,
3.598
),
(
42
,
3.595
),
(
41
,
3.591
),
(
40
,
3.588
),
(
39
,
3.584
),
(
38
,
3.581
),
(
37
,
3.576
),
(
36
,
3.573
),
(
35
,
3.569
),
(
34
,
3.566
),
(
33
,
3.563
),
(
32
,
3.562
),
(
31
,
3.556
),
(
30
,
3.552
),
(
29
,
3.549
),
(
28
,
3.545
),
(
27
,
3.541
),
(
26
,
3.537
),
(
25
,
3.533
),
(
24
,
3.529
),
(
23
,
3.525
),
(
22
,
3.520
),
(
21
,
3.515
),
(
20
,
3.510
),
(
20
,
3.505
),
(
19
,
3.499
),
(
18
,
3.493
),
(
17
,
3.486
),
(
16
,
3.479
),
(
15
,
3.472
),
(
14
,
3.464
),
(
13
,
3.455
),
(
12
,
3.446
),
(
11
,
3.437
),
(
10
,
3.426
),
(
9
,
3.415
),
(
8
,
3.404
),
(
7
,
3.391
),
(
6
,
3.378
),
(
5
,
3.365
),
(
4
,
3.348
),
(
3
,
3.324
),
(
2
,
3.286
),
(
1
,
3.223
),
(
1
,
3.121
),
(
0
,
2.958
),
(
0
,
0
),
]
]
for
(
p1
,
v1
),
(
p2
,
v2
)
in
zip
(
piecewise
,
piecewise
[
1
:]):
if
voltage
>
v1
or
voltage
<
v2
:
for
i
in
range
(
len
(
batLUT
)):
continue
if
voltage
>=
batLUT
[
i
][
1
]:
vr
=
v1
-
v2
percentage
=
batLUT
[
i
][
0
]
pr
=
p1
-
p2
break
vd
=
voltage
-
v2
p
=
vd
/
vr
self
.
_prev_battery_percentages
.
pop
(
0
)
return
pr
*
p
+
p2
self
.
_prev_battery_percentages
.
append
(
percentage
)
log
.
debug
(
"
percentage:
"
+
str
(
percentage
)
+
"
%
"
)
log
.
debug
(
"
prev:
"
+
str
(
self
.
_prev_battery_percentages
)
+
"
%
"
)
percent_list
=
self
.
_prev_battery_percentages
# avoid division by zero in weird edge cases
if
(
sum
(
percent_list
)
==
0
)
or
(
percent_list
[
0
]
==
0
):
return
0
return
0
for
i
in
range
(
len
(
percent_list
)):
if
sum
(
percent_list
)
/
percent_list
[
0
]
==
len
(
percent_list
):
# all values are the same, we settled on a value (might be the same as before but that's ok)
return
percentage
else
:
# we're still settling on a value, return previously settled value
return
self
.
_battery_percentage
This diff is collapsed.
Click to expand it.
python_payload/st3m/ui/elements/overlays.py
+
40
−
24
View file @
81c2eddc
...
@@ -11,7 +11,7 @@ from st3m.goose import Dict, Enum, List, ABCBase, abstractmethod, Optional
...
@@ -11,7 +11,7 @@ from st3m.goose import Dict, Enum, List, ABCBase, abstractmethod, Optional
from
st3m.utils
import
tau
from
st3m.utils
import
tau
from
st3m.ui.view
import
ViewManager
from
st3m.ui.view
import
ViewManager
from
st3m.input
import
power
from
st3m.input
import
power
from
st3m.power
import
approximate_battery_percentage
import
st3m.power
from
ctx
import
Context
from
ctx
import
Context
import
st3m.wifi
import
st3m.wifi
...
@@ -561,10 +561,10 @@ class BatteryIcon(Icon):
...
@@ -561,10 +561,10 @@ class BatteryIcon(Icon):
def
__init__
(
self
)
->
None
:
def
__init__
(
self
)
->
None
:
super
().
__init__
()
super
().
__init__
()
self
.
_percent
=
100.0
self
.
_percent
=
100.0
self
.
_cha
rging
=
Fals
e
self
.
_cha
nged
=
Tru
e
def
visible
(
self
)
->
bool
:
def
visible
(
self
)
->
bool
:
return
True
return
power
.
has_battery
def
draw
(
self
,
ctx
:
Context
)
->
None
:
def
draw
(
self
,
ctx
:
Context
)
->
None
:
if
self
.
_percent
>
30
:
if
self
.
_percent
>
30
:
...
@@ -583,30 +583,45 @@ class BatteryIcon(Icon):
...
@@ -583,30 +583,45 @@ class BatteryIcon(Icon):
ctx
.
rectangle
(
100
,
-
30
,
-
20
,
60
)
ctx
.
rectangle
(
100
,
-
30
,
-
20
,
60
)
ctx
.
fill
()
ctx
.
fill
()
if
self
.
_charging
:
ctx
.
font
=
ctx
.
get_font_name
(
1
)
ctx
.
move_to
(
-
72
,
32
)
ctx
.
font_size
=
100
ctx
.
rgb
(
255
,
255
,
255
).
text
(
str
(
self
.
_percent
))
def
think
(
self
,
ins
:
InputState
,
delta_ms
:
int
)
->
None
:
self
.
_percent
=
power
.
battery_percentage
class
ChargingIcon
(
Icon
):
WIDTH
:
int
=
20
def
__init__
(
self
)
->
None
:
super
().
__init__
()
self
.
_charging
=
power
.
battery_charging
self
.
_changed
=
True
def
visible
(
self
)
->
bool
:
if
not
power
.
has_battery
:
return
False
else
:
return
power
.
battery_charging
def
draw
(
self
,
ctx
:
Context
)
->
None
:
ctx
.
rgb
(
255
,
255
,
255
)
ctx
.
gray
(
1
)
ctx
.
gray
(
1
)
ctx
.
line_width
=
20
ctx
.
line_width
=
20
ctx
.
move_to
(
10
,
-
65
-
10
)
ctx
.
move_to
(
10
,
-
65
)
ctx
.
line_to
(
-
30
,
20
-
10
)
ctx
.
line_to
(
-
30
,
20
)
ctx
.
line_to
(
30
,
-
20
-
10
)
ctx
.
line_to
(
30
,
-
20
)
ctx
.
line_to
(
-
10
,
65
-
10
)
ctx
.
line_to
(
-
10
,
65
)
ctx
.
line_to
(
-
20
,
35
-
10
)
ctx
.
line_to
(
-
20
,
35
)
ctx
.
stroke
()
ctx
.
stroke
()
ctx
.
move_to
(
-
10
,
65
-
10
)
ctx
.
move_to
(
-
10
,
65
)
ctx
.
line_to
(
40
,
35
-
10
)
ctx
.
line_to
(
40
,
35
)
ctx
.
stroke
()
ctx
.
stroke
()
self
.
_changed
=
False
def
think
(
self
,
ins
:
InputState
,
delta_ms
:
int
)
->
None
:
def
think
(
self
,
ins
:
InputState
,
delta_ms
:
int
)
->
None
:
percent
=
approximate_battery_percentage
(
power
.
battery_voltage
)
self
.
_charging
=
power
.
battery_charging
charging
=
power
.
battery_charging
if
percent
!=
self
.
_percent
:
self
.
_percent
=
percent
self
.
_changed
=
True
if
charging
!=
self
.
_charging
:
self
.
_charging
=
charging
self
.
_changed
=
True
class
IconTray
(
Overlay
):
class
IconTray
(
Overlay
):
...
@@ -618,6 +633,7 @@ class IconTray(Overlay):
...
@@ -618,6 +633,7 @@ class IconTray(Overlay):
def
__init__
(
self
)
->
None
:
def
__init__
(
self
)
->
None
:
self
.
icons
=
[
self
.
icons
=
[
ChargingIcon
(),
BatteryIcon
(),
BatteryIcon
(),
USBIcon
(),
USBIcon
(),
WifiIcon
(),
WifiIcon
(),
...
...
This diff is collapsed.
Click to expand it.
sim/fakes/machine.py
+
4
−
1
View file @
81c2eddc
...
@@ -4,9 +4,12 @@ import sys
...
@@ -4,9 +4,12 @@ import sys
class
Pin
:
class
Pin
:
IN
=
None
IN
=
None
def
__init__
(
self
,
_1
,
_2
):
def
__init__
(
self
,
_1
,
_2
,
pull
=
None
):
pass
pass
def
value
(
self
):
return
0
class
ADC
:
class
ADC
:
ATTN_11DB
=
None
ATTN_11DB
=
None
...
...
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment