1# --- autodoc 兼容(同步脚本注入):CPython 下补齐 MicroPython 专有 API ---
2import time as _time_mod
3for _n in ('sleep_ms', 'sleep_us'):
4 if not hasattr(_time_mod, _n):
5 setattr(_time_mod, _n, lambda *a, **k: None)
6
7# labplus mPython library
8# MIT license; Copyright (c) 2018 labplus
9# V1.0 Zhang KaiHua(apple_eat@126.com)
10
11# mpython buildin periphers drivers
12
13# history:
14# V1.1 add oled draw function,add buzz.freq(). by tangliufeng
15# V1.2 add servo/ui class,by tangliufeng
16
17from machine import I2C, PWM, Pin, ADC, TouchPad
18from ssd1106 import SSD1106_I2C
19import esp, math, time, network
20import ustruct, array
21from neopixel import NeoPixel
22# from esp import dht_readinto
23from time import sleep_ms, sleep_us, sleep
24import framebuf
25import calibrate_img
26from micropython import schedule,const
27import NVS
28import ubinascii
29import machine
30
31try:
32 i2c = I2C(0, scl=Pin(Pin.P19), sda=Pin(Pin.P20), freq=400000)
33except Exception: # autodoc 兼容:无硬件环境降级为 None
34 i2c = None
35
36if '_print' not in dir(): _print = print
37
38def print(_t, *args, sep=' ', end='\n'):
39 _s = str(_t)[0:1]
40 if u'\u4e00' <= _s <= u'\u9fff':
41 _print(' ' + str(_t), *args, sep=sep, end=end)
42 else:
43 _print(_t, *args, sep=sep, end=end)
44
45# my_wifi = wifi()
46#多次尝试连接wifi
47def try_connect_wifi(_wifi, _ssid, _pass, _times):
48 if _times < 1: return False
49 try:
50 print("Try Connect WiFi ... {} Times".format(_times) )
51 _wifi.connectWiFi(_ssid, _pass)
52 if _wifi.sta.isconnected(): return True
53 else:
54 time.sleep(5)
55 return try_connect_wifi(_wifi, _ssid, _pass, _times-1)
56 except:
57 time.sleep(5)
58 return try_connect_wifi(_wifi, _ssid, _pass, _times-1)
59
60class Font(object):
61 def __init__(self, font_address=0x400000):
62 self.font_address = font_address
63 buffer = bytearray(18)
64 esp.flash_read(self.font_address, buffer)
65 self.header, \
66 self.height, \
67 self.width, \
68 self.baseline, \
69 self.x_height, \
70 self.Y_height, \
71 self.first_char,\
72 self.last_char = ustruct.unpack('4sHHHHHHH', buffer)
73 self.first_char_info_address = self.font_address + 18
74
75 def GetCharacterData(self, c):
76 uni = ord(c)
77 # if uni not in range(self.first_char, self.last_char):
78 # return None
79 if (uni < self.first_char or uni > self.last_char):
80 return None
81 char_info_address = self.first_char_info_address + \
82 (uni - self.first_char) * 6
83 buffer = bytearray(6)
84 esp.flash_read(char_info_address, buffer)
85 ptr_char_data, len = ustruct.unpack('IH', buffer)
86 if (ptr_char_data) == 0 or (len == 0):
87 return None
88 buffer = bytearray(len)
89 esp.flash_read(ptr_char_data + self.font_address, buffer)
90 return buffer
91
92
93class TextMode():
94 normal = 1
95 rev = 2
96 trans = 3
97 xor = 4
98
99
100class OLED(SSD1106_I2C):
101 """ 128x64 oled display """
102
103 def __init__(self):
104 super().__init__(128, 64, i2c)
105 self.f = Font()
106 if self.f is None:
107 raise Exception('font load failed')
108
109 def DispChar(self, s, x, y, mode=TextMode.normal, auto_return=False):
110 row = 0
111 str_width = 0
112 if self.f is None:
113 return
114 for c in s:
115 data = self.f.GetCharacterData(c)
116 if data is None:
117 if auto_return is True:
118 x = x + self.f.width
119 else:
120 x = x + self.width
121 continue
122 width, bytes_per_line = ustruct.unpack('HH', data[:4])
123 # print('character [%d]: width = %d, bytes_per_line = %d' % (ord(c)
124 # , width, bytes_per_line))
125 if auto_return is True:
126 if x > self.width - width:
127 str_width += self.width - x
128 x = 0
129 row += 1
130 y += self.f.height
131 if y > (self.height - self.f.height)+0:
132 y, row = 0, 0
133 for h in range(0, self.f.height):
134 w = 0
135 i = 0
136 while w < width:
137 mask = data[4 + h * bytes_per_line + i]
138 if (width - w) >= 8:
139 n = 8
140 else:
141 n = width - w
142 py = y + h
143 page = py >> 3
144 bit = 0x80 >> (py % 8)
145 for p in range(0, n):
146 px = x + w + p
147 c = 0
148 if (mask & 0x80) != 0:
149 if mode == TextMode.normal or \
150 mode == TextMode.trans:
151 c = 1
152 if mode == TextMode.rev:
153 c = 0
154 if mode == TextMode.xor:
155 c = self.buffer[page * (self.width if auto_return is True else 128) + px] & bit
156 if c != 0:
157 c = 0
158 else:
159 c = 1
160 super().pixel(px, py, c)
161 else:
162 if mode == TextMode.normal:
163 c = 0
164 super().pixel(px, py, c)
165 if mode == TextMode.rev:
166 c = 1
167 super().pixel(px, py, c)
168 mask = mask << 1
169 w = w + 8
170 i = i + 1
171 x = x + width + 1
172 str_width += width + 1
173 return (str_width-1,(x-1, y))
174
175 def DispChar_font(self, font, s, x, y, invert=False):
176 """
177 custom font display.Ref by , https://github.com/peterhinch/micropython-font-to-py
178 :param font: use font_to_py.py script convert to `py` from `ttf` or `otf`.
179 """
180 screen_width = self.width
181 screen_height = self.height
182 text_row = x
183 text_col = y
184 text_length = 0
185 if font.hmap():
186 font_map = framebuf.MONO_HMSB if font.reverse() else framebuf.MONO_HLSB
187 else:
188 raise ValueError('Font must be horizontally mapped.')
189 for c in s:
190 glyph, char_height, char_width = font.get_ch(c)
191 buf = bytearray(glyph)
192 if invert:
193 for i, v in enumerate(buf):
194 buf[i] = 0xFF & ~ v
195 fbc = framebuf.FrameBuffer(buf, char_width, char_height, font_map)
196 if text_row + char_width > screen_width - 1:
197 text_length += screen_width-text_row
198 text_row = 0
199 text_col += char_height
200 if text_col + char_height > screen_height + 2:
201 text_col = 0
202
203 super().blit(fbc, text_row, text_col)
204 text_row = text_row + char_width+1
205 text_length += char_width+1
206 return (text_length-1, (text_row-1, text_col))
207
208# display
209if 60 in i2c.scan():
210 oled = OLED()
211 display = oled
212else:
213 print("oled init error!")
214
215class MOTION(object):
216 def __init__(self):
217 self.i2c = i2c
218 addr = self.i2c.scan()
219 if 38 in addr:
220 MOTION.chip = 1 # MSA300
221 MOTION.IIC_ADDR = 38
222 elif 107 in addr:
223 MOTION.chip = 2 # QMI8658
224 MOTION.IIC_ADDR = 107
225 else:
226 raise OSError("MOTION init error")
227 if(MOTION.chip == 1):
228 pass
229 elif(MOTION.chip == 2):
230 MOTION._writeReg(0x60, 0x01) # soft reset regist value.
231 time.sleep_ms(20)
232 MOTION._writeReg(0x02, 0x60) # Enabe reg address auto increment auto
233 MOTION._writeReg(0x08, 0x03) # Enable accel and gyro
234 MOTION._writeReg(0x03, 0x1c) # accel range:4g ODR 128HZ
235 MOTION._writeReg(0x04, 0x40) # gyro ODR 8000HZ, FS 256dps
236 MOTION._writeReg(0x06, 0x55) # Enable accel and gyro Low-Pass Filter
237 # print('Motion init finished!')
238
239 # @staticmethod
240 def _readReg(reg, nbytes=1):
241 return i2c.readfrom_mem(MOTION.IIC_ADDR, reg, nbytes)
242
243 # @staticmethod
244 def _writeReg(reg, value):
245 i2c.writeto_mem(MOTION.IIC_ADDR, reg, value.to_bytes(1, 'little'))
246
247 def get_fw_version(self):
248 if(self.chip==1):
249 pass
250 elif(self.chip==2):
251 MOTION._writeReg(0x0a, 0x10) # send ctrl9R read FW cmd
252 while True:
253 if (MOTION._readReg(0x2F, 1)[0] & 0X01) == 0X01:
254 break
255 buf = MOTION._readReg(0X49, 3)
256 # print(buf[0])
257 # print(buf[1])
258 # print(buf[2])
259
260 class Accelerometer():
261 """MSA300"""
262 # Range and resolustion
263 RANGE_2G = const(0)
264 RANGE_4G = const(1)
265 RANGE_8G = const(2)
266 RANGE_16G = const(3)
267 RES_14_BIT = const(0)
268 RES_12_BIT = const(1)
269 RES_10_BIT = const(2)
270 # Event
271 TILT_LEFT = const(0)
272 TILT_RIGHT = const(1)
273 TILT_UP = const(2)
274 TILT_DOWN = const(3)
275 FACE_UP = const(4)
276 FACE_DOWN = const(5)
277 SINGLE_CLICK = const(6)
278 DOUBLE_CLICK = const(7)
279 FREEFALL = const(8)
280
281 """QMI8658C"""
282 # Range and resolustion
283 # QMI8658C_RANGE_2G = const(0x00)
284 # QMI8658C_RANGE_4G = const(0x10)
285 # QMI8658C_RANGE_8G = const(0x20)
286 # QMI8658C_RANGE_16G = const(0x40)
287
288 def __init__(self):
289 if(MOTION.chip==1):
290 self.set_resolution(MOTION.Accelerometer.RES_10_BIT)
291 self.set_range(MOTION.Accelerometer.RANGE_2G)
292 MOTION._writeReg(0x12, 0x03) # polarity of y,z axis,
293 MOTION._writeReg(0x11, 0) # set power mode = normal
294 # interrupt
295 MOTION._writeReg(0x16, 0x70) # int enabled: Orient | S_TAP | D_TAP
296 MOTION._writeReg(0x17, 0x08) # int enabled: Freefall
297 MOTION._writeReg(0x19, 0x71) # int1 map to: Orient, S_TAP, D_TAP, Freefall
298 MOTION._writeReg(0x20, 0x02) # int1 active level = 0, output = OD
299 MOTION._writeReg(0x21, 0x0C) # int tempoary latched 25ms
300 # freefall:
301 # single mode: |acc_x| < Threshold && |acc_y| < Threshold && |acc_z| < Threshold, at least time > Duration
302 # sum mode: |acc_x| + |acc_y| + |acc_z| < Threshold, at least time > Duration
303 MOTION._writeReg(0x22, 20) # Freefall Duration:(n+1)*2ms, range from 2ms to 512ms
304 MOTION._writeReg(0x23, 48) # Freefall Threshold: n*7.81mg
305 MOTION._writeReg(0x24, 0x01) # Freefall mode = 0-singlemode;hysteresis = n*125mg
306 # tap:
307 MOTION._writeReg(0x2A, 0x06) # Tap duration:quit = 30ms, shock=50ms, time window for secent shock=500ms
308 MOTION._writeReg(0x2B, 0x0A) # Tap threshold = 10*[62.5mg@2G | 125mg@4G | 250mg@8G | 500mg@16g]
309 # Orient
310 MOTION._writeReg(0x2C, 0x18) # Orient hysteresis= 1*62.5mg;
311 # block mode = 10 z_axis blocking or slope in any axis > 0.2g;
312 # orient mode = 00-symetrical
313 MOTION._writeReg(0x2D, 8) # Z-axis block
314 # int pin irq register
315 self.int = Pin(37, Pin.IN)
316 self.int.irq(trigger=Pin.IRQ_FALLING, handler=self.irq)
317 # event handler
318 self.event_tilt_up = None
319 self.event_tilt_down = None
320 self.event_tilt_left = None
321 self.event_tilt_right = None
322 self.event_face_up = None
323 self.event_face_down = None
324 self.event_single_click = None
325 self.event_double_click = None
326 self.event_freefall = None
327 elif(MOTION.chip==2):
328 # 设置偏移值
329 self.x_offset = 0
330 self.y_offset = 0
331 self.z_offset = 0
332 self.get_nvs_offset()
333 try:
334 id = MOTION._readReg(0x0, 2)
335 except:
336 pass
337 self.set_range(MOTION.Accelerometer.RANGE_2G) #设置默认分辨率+-2g
338 self.int = Pin(37, Pin.IN)
339 self.int.irq(trigger=Pin.IRQ_FALLING, handler=self.irq)
340 # event handler
341 self.wom = None
342
343
344 def irq(self, arg):
345 if(MOTION.chip==1):
346 reg_int = MOTION._readReg(0x09)[0]
347 reg_orent = MOTION._readReg(0x0C)[0]
348 # orient_int
349 if (reg_int & 0x40):
350 if ((reg_orent & 0x30) == 0x00 and self.event_tilt_left is not None):
351 schedule(self.event_tilt_left, self.TILT_LEFT)
352 if ((reg_orent & 0x30) == 0x10 and self.event_tilt_right is not None):
353 schedule(self.event_tilt_right, self.TILT_RIGHT)
354 if ((reg_orent & 0x30) == 0x20 and self.event_tilt_up is not None):
355 schedule(self.event_tilt_up, self.TILT_UP)
356 if ((reg_orent & 0x30) == 0x30 and self.event_tilt_down is not None):
357 schedule(self.event_tilt_down, self.TILT_DOWN)
358 if ((reg_orent & 0x40) == 0x00 and self.event_face_up):
359 schedule(self.event_face_up, self.FACE_UP)
360 if ((reg_orent & 0x40) == 0x40 and self.event_face_down):
361 schedule(self.event_face_down, self.FACE_DOWN)
362 # single tap
363 if (reg_int & 0x20):
364 if (self.event_single_click is not None):
365 schedule(self.event_single_click, self.SINGLE_CLICK)
366 # double tap
367 if (reg_int & 0x10):
368 if (self.event_double_click is not None):
369 schedule(self.event_double_click, self.DOUBLE_CLICK)
370 # freefall
371 if (reg_int & 0x01):
372 if (self.event_freefall is not None):
373 schedule(self.event_freefall, self.FREEFALL)
374 # print("acc sensor interrupt, because 0x%2x, orient = 0x%2x" % (reg_int, reg_orent))
375 elif(MOTION.chip==2):
376 flag = MOTION._readReg(0x2F, 1)[0]
377 if (flag & 0x04) == 0x04:
378 print('wom int trigged.')
379
380 def wom_config(self):
381 if(MOTION.chip==1):
382 pass
383 elif(MOTION.chip==2):
384 MOTION._writeReg(0x60, 0x01) # soft reset regist value.
385 time.sleep_ms(20)
386 MOTION._writeReg(0x08, 0x0) # disable all sensor
387 MOTION._writeReg(0x03, 0x1c) # accel range:4g ODR 128HZ
388 MOTION._writeReg(0x0B, 0xfF) # CAL_L WoM Threshold(1mg/LSB resolution)
389 MOTION._writeReg(0x0C, 0x8F) # CAL_H WoM (INT1 blank time 0x1f)
390 MOTION._writeReg(0x0A, 0x08)
391 while True:
392 if (MOTION._readReg(0x2F, 1)[0] & 0X01) == 0X01:
393 break
394 MOTION._writeReg(0x08, 0x01) # enable accel
395
396 def set_resolution(self, resolution):# set data output rate
397 if(MOTION.chip==1):
398 format = MOTION._readReg(0x0f, 1)
399 format = format[0] & ~0xC
400 format |= (resolution << 2)
401 MOTION._writeReg(0x0f, format)
402 elif(MOTION.chip==2):
403 self.odr = resolution
404 format = MOTION._readReg(0x03, 1)
405 format = format[0] & 0xf0
406 format |= (resolution & 0x0f)
407 MOTION._writeReg(0x03, format)
408
409 def set_range(self, range):
410 if(MOTION.chip==1):
411 self.range = range
412 format = MOTION._readReg(0x0f, 1)
413 format = format[0] & ~0x3
414 format |= range
415 MOTION._writeReg(0x0f, format)
416 elif(MOTION.chip==2):
417 if(range==3):
418 range = 64 #0x40
419 else:
420 range = range << 4
421 self.FS = 2*(2**(range >> 4))
422 format = MOTION._readReg(0x03, 1)
423 format = format[0] & 0x8F
424 format |= range
425 MOTION._writeReg(0x03, format)
426
427 def set_offset(self, x=None, y=None, z=None):
428 if(MOTION.chip==1):
429 for i in (x, y, z):
430 if i is not None:
431 if i < -1 or i > 1:
432 raise ValueError("out of range,only offset 1 gravity")
433 if x is not None:
434 MOTION._writeReg(0x39, int(round(x/0.0039)))
435 elif y is not None:
436 MOTION._writeReg(0x38, int(round(y/0.0039)))
437 elif z is not None:
438 MOTION._writeReg(0x3A, int(round(z/0.0039)))
439 elif(MOTION.chip==2):
440 for i in (x, y, z):
441 if i is not None:
442 if i < -16 or i > 16:
443 raise ValueError("超出调整范围!!!")
444 if x is not None:
445 self.x_offset = x
446 self.set_nvs_offset("x", x)
447 if y is not None:
448 self.y_offset = y
449 self.set_nvs_offset("y", y)
450 if z is not None:
451 self.z_offset = z
452 self.set_nvs_offset("z", z)
453
454 def get_x(self):
455 if(MOTION.chip==1):
456 retry = 0
457 if (retry < 5):
458 try:
459 buf = MOTION._readReg(0x02, 2)
460 x = ustruct.unpack('h', buf)[0]
461 return x / 4 / 4096 * 2**self.range
462 except:
463 retry = retry + 1
464 else:
465 raise Exception("i2c read/write error!")
466 elif(MOTION.chip==2):
467 buf = MOTION._readReg(0x35, 2)
468 x = ustruct.unpack('<h', buf)[0]
469 return (x * self.FS) / 32768 + self.x_offset
470
471 def get_y(self):
472 if(MOTION.chip==1):
473 retry = 0
474 if (retry < 5):
475 try:
476 buf = MOTION._readReg(0x04, 2)
477 y = ustruct.unpack('h', buf)[0]
478 return y / 4 / 4096 * 2**self.range
479 except:
480 retry = retry + 1
481 else:
482 raise Exception("i2c read/write error!")
483 elif(MOTION.chip==2):
484 buf = MOTION._readReg(0x37, 2)
485 y = ustruct.unpack('<h', buf)[0]
486 return (y * self.FS) / 32768 + self.y_offset
487
488 def get_z(self):
489 if(MOTION.chip==1):
490 retry = 0
491 if (retry < 5):
492 try:
493 buf = MOTION._readReg(0x06, 2)
494 z = ustruct.unpack('h', buf)[0]
495 return z / 4 / 4096 * 2**self.range
496 except:
497 retry = retry + 1
498 else:
499 raise Exception("i2c read/write error!")
500 elif(MOTION.chip==2):
501 buf = MOTION._readReg(0x39, 2)
502 z = ustruct.unpack('<h', buf)[0]
503 return (z * self.FS) / 32768 + self.z_offset
504 # return -(z * self.FS) / 32768
505
506 def roll_pitch_angle(self):
507 x, y, z = self.get_x(), self.get_y(), -self.get_z()
508 # vector normalize
509 mag = math.sqrt(x ** 2 + y ** 2+z ** 2)
510 x /= mag
511 y /= mag
512 z /= mag
513 roll = math.degrees(-math.asin(y))
514 pitch = math.degrees(math.atan2(x, z))
515
516 return roll, pitch
517
518 def get_nvs_offset(self):
519 try:
520 tmp = NVS("offset_a")
521 self.x_offset = round(tmp.get_i32("x")/1e5, 5)
522 self.y_offset = round(tmp.get_i32("y")/1e5, 5)
523 self.z_offset = round(tmp.get_i32("z")/1e5, 5)
524 except OSError as e:
525 # print('Accelerometer get_nvs_offset:',e)
526 # self.x_offset = 0
527 # self.y_offset = 0
528 # self.z_offset = 0
529 self.set_offset(0,0,0)
530
531 def set_nvs_offset(self, key, value):
532 try:
533 nvs = NVS("offset_a")
534 nvs.set_i32(key, int(value*1e5))
535 nvs.commit()
536 except OSError as e:
537 print('Gyroscope set_nvs_offset error:',e)
538
539 class Gyroscope():
540 # gyro full scale
541 RANGE_16_DPS = const(0x00)
542 RANGE_32_DPS = const(0x10)
543 RANGE_64_DPS = const(0x20)
544 RANGE_128_DPS = const(0x30)
545 RANGE_256_DPS = const(0x40)
546 RANGE_512_DPS = const(0x50)
547 RANGE_1024_DPS = const(0x60)
548 RANGE_2048_DPS = const(0x70)
549
550 def __init__(self):
551 if(MOTION.chip==1):
552 pass
553 elif(MOTION.chip==2):
554 # 设置偏移值
555 self.x_offset = 0
556 self.y_offset = 0
557 self.z_offset = 0
558 self.get_nvs_offset()
559 self.set_range(MOTION.Gyroscope.RANGE_256_DPS)
560
561 def set_range(self, range):
562 if(MOTION.chip==1):
563 pass
564 elif(MOTION.chip==2):
565 self.FS = 16*(2**(range >> 4))
566 format = MOTION._readReg(0x04, 1)
567 format = format[0] & 0x8F
568 format |= range
569 MOTION._writeReg(0x04, format)
570
571 def set_ODR(self, odr): # set data output rate
572 if(MOTION.chip==1):
573 pass
574 elif(MOTION.chip==2):
575 self.odr = odr
576 format = MOTION._readReg(0x04, 1)
577 format = format[0] & 0xF0
578 format |= odr
579 MOTION._writeReg(0x04, format)
580
581 def get_x(self):
582 if(MOTION.chip==1):
583 pass
584 elif(MOTION.chip==2):
585 buf = MOTION._readReg(0x3b, 2)
586 x = ustruct.unpack('<h', buf)[0]
587 return (x * self.FS) / 32768 + self.x_offset
588
589 def get_y(self):
590 if(MOTION.chip==1):
591 pass
592 elif(MOTION.chip==2):
593 buf = MOTION._readReg(0x3d, 2)
594 y = ustruct.unpack('<h', buf)[0]
595 return (y * self.FS) / 32768 + self.y_offset
596
597 def get_z(self):
598 if(MOTION.chip==1):
599 pass
600 elif(MOTION.chip==2):
601 buf = MOTION._readReg(0x3f, 2)
602 z = ustruct.unpack('<h', buf)[0]
603 return (z * self.FS) / 32768 + self.z_offset
604
605 def set_offset(self, x=None, y=None, z=None):
606 if(MOTION.chip==1):
607 pass
608 elif(MOTION.chip==2):
609 for i in (x, y, z):
610 if i is not None:
611 if i < -4096 or i > 4096:
612 raise ValueError("超出调整范围!!!")
613 if x is not None:
614 self.x_offset = x
615 self.set_nvs_offset("x", x)
616 if y is not None:
617 self.y_offset = y
618 self.set_nvs_offset("y", y)
619 if z is not None:
620 self.z_offset = z
621 self.set_nvs_offset("z", z)
622
623 def get_nvs_offset(self):
624 if(MOTION.chip==1):
625 pass
626 elif(MOTION.chip==2):
627 try:
628 tmp = NVS("offset_g")
629 self.x_offset = round(tmp.get_i32("x")/1e5, 5)
630 self.y_offset = round(tmp.get_i32("y")/1e5, 5)
631 self.z_offset = round(tmp.get_i32("z")/1e5, 5)
632 except OSError as e:
633 # print('Gyroscope get_nvs_offset:',e)
634 self.set_offset(0,0,0)
635 # self.x_offset = 0
636 # self.y_offset = 0
637 # self.z_offset = 0
638
639 def set_nvs_offset(self, key, value):
640 try:
641 nvs = NVS("offset_g")
642 nvs.set_i32(key, int(value*1e5))
643 nvs.commit()
644 except OSError as e:
645 print('Gyroscope set_nvs_offset error:',e)
646
647
648try:
649 motion = MOTION()
650except Exception: # autodoc 兼容:无硬件环境降级为 None
651 motion = None
652try:
653 accelerometer = motion.Accelerometer()
654except Exception: # autodoc 兼容:无硬件环境降级为 None
655 accelerometer = None
656try:
657 gyroscope = motion.Gyroscope()
658except Exception: # autodoc 兼容:无硬件环境降级为 None
659 gyroscope = None
660
661class Magnetic(object):
662 """ MMC5983MA driver """
663 """ MMC5603NJ driver 20211028替换"""
664 def __init__(self):
665 self.addr = 48
666 self.i2c = i2c
667 self._judge_id()
668 time.sleep_ms(5)
669 if (self.product_ID==48):
670 pass # MMC5983MA
671 elif (self.product_ID==16):
672 pass # MMC5603NJ
673 else:
674 raise OSError("Magnetic init error")
675 """ MMC5983MA driver """
676 # 传量器裸数据,乘0.25后转化为mGS
677 self.raw_x = 0.0
678 self.raw_y = 0.0
679 self.raw_z = 0.0
680 # 校准后的偏移量, 基于裸数据
681 self.cali_offset_x = 0.0
682 self.cali_offset_y = 0.0
683 self.cali_offset_z = 0.0
684 # 去皮偏移量,类似电子秤去皮功能,基于裸数据。
685 self.peeling_x = 0.0
686 self.peeling_y = 0.0
687 self.peeling_z = 0.0
688 self.is_peeling = 0
689 if (self.chip==1):
690 self.i2c.writeto(self.addr, b'\x09\x20\xbd\x00', True)
691 """ MMC5603NJ driver """
692 if (self.chip==2):
693 self._writeReg(0x1C, 0x80)#软件复位
694 time.sleep_ms(100)
695 self._writeReg(0x1A, 255)
696 self._writeReg(0x1B, 0b10100001)
697 # self._writeReg(0x1C, 0b00000011)
698 self._writeReg(0x1C, 0b00000000)
699 self._writeReg(0x1D, 0b10010000)
700 time.sleep_ms(100)
701
702 def _readReg(self, reg, nbytes=1):
703 return i2c.readfrom_mem(self.addr, reg, nbytes)
704
705 def _writeReg(self, reg, value):
706 i2c.writeto_mem(self.addr, reg, value.to_bytes(1, 'little'))
707
708 def _set_offset(self):
709 if(self.chip == 1):
710 self.i2c.writeto(self.addr, b'\x09\x08', True) #set
711 self.i2c.writeto(self.addr, b'\x09\x01', True)
712 while True:
713 self.i2c.writeto(self.addr, b'\x08', False)
714 buf = self.i2c.readfrom(self.addr, 1)
715 status = ustruct.unpack('B', buf)[0]
716 if(status & 0x01):
717 break
718 self.i2c.writeto(self.addr, b'\x00', False)
719 buf = self.i2c.readfrom(self.addr, 6)
720 data = ustruct.unpack('>3H', buf)
721
722 self.i2c.writeto(self.addr, b'\x09\x10', True) #reset
723
724 self.i2c.writeto(self.addr, b'\x09\x01', True)
725 while True:
726 self.i2c.writeto(self.addr, b'\x08', False)
727 buf = self.i2c.readfrom(self.addr, 1)
728 status = ustruct.unpack('B', buf)[0]
729 if(status & 0x01):
730 break
731 self.i2c.writeto(self.addr, b'\x00', False)
732 buf = self.i2c.readfrom(self.addr, 6)
733 data1 = ustruct.unpack('>3H', buf)
734
735 self.x_offset = (data[0] + data1[0])/2
736 self.y_offset = (data[1] + data1[1])/2
737 self.z_offset = (data[2] + data1[2])/2
738 elif(self.chip == 2):
739 pass
740
741 def _get_raw(self):
742 if (self.chip == 1):
743 retry = 0
744 if (retry < 5):
745 try:
746 self.i2c.writeto(self.addr, b'\x09\x08', True) #set
747
748 self.i2c.writeto(self.addr, b'\x09\x01', True)
749 while True:
750 self.i2c.writeto(self.addr, b'\x08', False)
751 buf = self.i2c.readfrom(self.addr, 1)
752 status = ustruct.unpack('B', buf)[0]
753 if(status & 0x01):
754 break
755 self.i2c.writeto(self.addr, b'\x00', False)
756 buf = self.i2c.readfrom(self.addr, 6)
757 data = ustruct.unpack('>3H', buf)
758
759 self.i2c.writeto(self.addr, b'\x09\x10', True) #reset
760
761 self.i2c.writeto(self.addr, b'\x09\x01', True)
762 while True:
763 self.i2c.writeto(self.addr, b'\x08', False)
764 buf = self.i2c.readfrom(self.addr, 1)
765 status = ustruct.unpack('B', buf)[0]
766 if(status & 0x01):
767 break
768 self.i2c.writeto(self.addr, b'\x00', False)
769 buf = self.i2c.readfrom(self.addr, 6)
770 data1 = ustruct.unpack('>3H', buf)
771
772 self.raw_x = -((data[0] - data1[0])/2)
773 self.raw_y = -((data[1] - data1[1])/2)
774 self.raw_z = -((data[2] - data1[2])/2)
775 # print(str(self.raw_x) + " " + str(self.raw_y) + " " + str(self.raw_z))
776 except:
777 retry = retry + 1
778 else:
779 raise Exception("i2c read/write error!")
780 elif(self.chip == 2):
781 retry = 0
782 if (retry < 5):
783 try:
784 _raw_x = 0.0
785 _raw_y = 0.0
786 _raw_z = 0.0
787
788 # self.i2c.writeto(self.addr, b'\x1B\x08', True) #set
789 # self.i2c.writeto(self.addr, b'\x1B\x01', True)
790
791 # while True:
792 # buf = self._readReg(0x18, 1)
793 # status = buf[0]
794 # if(status & 0x40):
795 # break
796
797 # _buf = self._readReg(0x00, 9)
798
799 self.i2c.writeto(self.addr, b'\x1B\x08', True) #set
800 # self.i2c.writeto(self.addr, b'\x1B\x80', True)
801 self.i2c.writeto(self.addr, b'\x1B\x01', True)
802
803 while True:
804 sleep_ms(25)
805 buf = self._readReg(0x18, 1)
806 status = buf[0]
807 if(status & 0x40):
808 break
809
810 buf = self._readReg(0x00, 9)
811
812 _raw_x = (buf[0] << 12) | (buf[1] << 4) | (buf[6] >> 4)
813 _raw_y = (buf[2] << 12) | (buf[3] << 4) | (buf[7] >> 4)
814 _raw_z = (buf[4] << 12) | (buf[5] << 4) | (buf[8] >> 4)
815
816 self.raw_x = _raw_x
817 self.raw_y = _raw_y
818 self.raw_z = _raw_z
819 except:
820 retry = retry + 1
821 else:
822 raise Exception("i2c read/write error!")
823
824 def peeling(self):
825 '''
826 去除磁场环境
827 '''
828 self._get_raw()
829 self.peeling_x = self.raw_x
830 self.peeling_y = self.raw_y
831 self.peeling_z = self.raw_z
832 self.is_peeling = 1
833
834 def clear_peeling(self):
835 self.peeling_x = 0.0
836 self.peeling_y = 0.0
837 self.peeling_z = 0.0
838 self.is_peeling = 0
839
840 def get_x(self):
841 if (self.chip == 1):
842 self._get_raw()
843 return self.raw_x * 0.25
844 if (self.chip == 2):
845 self._get_raw()
846 if(self.cali_offset_x):
847 return -0.0625 * (self.raw_x - self.cali_offset_x)
848 else:
849 return -0.0625 * (self.raw_x - 524288)
850 # return -(self.raw_x - 524288)/16384
851
852 def get_y(self):
853 if (self.chip == 1):
854 self._get_raw()
855 return self.raw_y * 0.25
856 if (self.chip == 2):
857 self._get_raw()
858 if(self.cali_offset_y):
859 return -0.0625 * (self.raw_y - self.cali_offset_y)
860 else:
861 return -0.0625 * (self.raw_y - 524288)
862 # return -(self.raw_y - 524288)/16384
863
864 def get_z(self):
865 if (self.chip == 1):
866 self._get_raw()
867 return self.raw_z * 0.25
868 if (self.chip == 2):
869 self._get_raw()
870 if(self.cali_offset_z):
871 return 0.0625 * (self.raw_z - self.cali_offset_z)
872 else:
873 return 0.0625 * (self.raw_z - 524288)
874 # return (self.raw_z - 524288)/16384
875
876 def get_field_strength(self):
877 if(self.chip==1):
878 self._get_raw()
879 if self.is_peeling == 1:
880 return (math.sqrt((self.raw_x - self.peeling_x)*(self.raw_x - self.peeling_x) + (self.raw_y - self.peeling_y)*(self.raw_y - self.peeling_y) + (self.raw_z - self.peeling_z)*(self.raw_z - self.peeling_z)))*0.25
881 return (math.sqrt(self.raw_x * self.raw_x + self.raw_y * self.raw_y + self.raw_z * self.raw_z))*0.25
882 elif(self.chip==2):
883 self._get_raw()
884 if self.is_peeling == 1:
885 return (math.sqrt(math.pow(self.raw_x - self.peeling_x, 2) + pow(self.raw_y - self.peeling_y, 2) + pow(self.raw_z - self.peeling_z , 2)))*0.0625
886 return (math.sqrt(math.pow(self.get_x(), 2) + pow(self.get_y(), 2) + pow(self.get_z(), 2)))
887
888 def calibrate(self):
889 oled.fill(0)
890 oled.DispChar("步骤1:", 0,0,1)
891 oled.DispChar("如图",0,26,1)
892 oled.DispChar("转几周",0,43,1)
893 oled.bitmap(64,0,calibrate_img.rotate,64,64,1)
894 oled.show()
895 self._get_raw()
896 min_x = max_x = self.raw_x
897 min_y = max_y = self.raw_y
898 min_z = max_z = self.raw_z
899 ticks_start = time.ticks_ms()
900 while (time.ticks_diff(time.ticks_ms(), ticks_start) < 15000) :
901 self._get_raw()
902 min_x = min(self.raw_x, min_x)
903 min_y = min(self.raw_y, min_y)
904 max_x = max(self.raw_x, max_x)
905 max_y = max(self.raw_y, max_y)
906 time.sleep_ms(100)
907 self.cali_offset_x = (max_x + min_x) / 2
908 self.cali_offset_y = (max_y + min_y) / 2
909 print('cali_offset_x: ' + str(self.cali_offset_x) + ' cali_offset_y: ' + str(self.cali_offset_y))
910 oled.fill(0)
911 oled.DispChar("步骤2:", 85,0,1)
912 oled.DispChar("如图",85,26,1)
913 oled.DispChar("转几周",85,43,1)
914 oled.bitmap(0,0,calibrate_img.rotate1,64,64,1)
915 oled.show()
916 ticks_start = time.ticks_ms()
917 while (time.ticks_diff(time.ticks_ms(), ticks_start) < 15000) :
918 self._get_raw()
919 min_z = min(self.raw_z, min_z)
920 max_z = max(self.raw_z, max_z)
921 time.sleep_ms(100)
922 self.cali_offset_z = (max_z + min_z) / 2
923
924 print('cali_offset_z: ' + str(self.cali_offset_z))
925
926 oled.fill(0)
927 oled.DispChar("校准完成", 40,24,1)
928 oled.show()
929 oled.fill(0)
930
931 def get_heading(self):
932 if(self.chip==1):
933 self._get_raw()
934 temp_x = self.raw_x - self.cali_offset_x
935 temp_y = self.raw_y - self.cali_offset_y
936 # temp_z = self.raw_z - self.cali_offset_z
937 heading = math.atan2(temp_y, -temp_x) * (180 / 3.14159265) + 180 + 3
938 return heading
939 else:
940 if(self.cali_offset_x):
941 self._get_raw()
942 temp_x = -(self.raw_x - self.cali_offset_x)
943 temp_y = -(self.raw_y - self.cali_offset_y)
944 heading = math.atan2(temp_y, -temp_x) * (180 / 3.14159265) + 180 + 3
945 else:
946 heading = math.atan2(self.get_y(), -self.get_x()) * (180 / 3.14159265) + 180 + 3
947 return heading
948
949 def _get_temperature(self):
950 if(self.chip==1):
951 retry = 0
952 if (retry < 5):
953 try:
954 self.i2c.writeto(self.addr, b'\x09\x02', True)
955 while True:
956 self.i2c.writeto(self.addr, b'\x08', False)
957 buf = self.i2c.readfrom(self.addr, 1)
958 status = ustruct.unpack('B', buf)[0]
959 if(status & 0x02):
960 break
961 self.i2c.writeto(self.addr, b'\x07', False)
962 buf = self.i2c.readfrom(self.addr, 1)
963 temp = (ustruct.unpack('B', buf)[0])*0.8 -75
964 # print(data)
965 return temp
966 except:
967 retry = retry + 1
968 else:
969 raise Exception("i2c read/write error!")
970 elif(self.chip == 2):
971 pass
972
973 def _get_id(self):
974 if (self.chip==1):
975 retry = 0
976 if (retry < 5):
977 try:
978 self.i2c.writeto(self.addr, bytearray([0x2f]), False)
979 buf = self.i2c.readfrom(self.addr, 1, True)
980 print(buf)
981 id = ustruct.unpack('B', buf)[0]
982 return id
983 except:
984 retry = retry + 1
985 else:
986 raise Exception("i2c read/write error!")
987 elif (self.chip==2):
988 retry = 0
989 if (retry < 5):
990 try:
991 self.i2c.writeto(self.addr, bytearray([0x39]), False)
992 buf = self.i2c.readfrom(self.addr, 1, True)
993 id = ustruct.unpack('B', buf)[0]
994 return id
995 except:
996 retry = retry + 1
997 else:
998 raise Exception("i2c read/write error!")
999
1000 def _judge_id(self):
1001 """
1002 判断product_ID
1003 """
1004 retry = 0
1005 if (retry < 5):
1006 try:
1007 self.i2c.writeto(self.addr, bytearray([0x39]), False)
1008 buf = self.i2c.readfrom(self.addr, 1, True)
1009 id = ustruct.unpack('B', buf)[0]
1010 if(id == 16):
1011 self.chip = 2
1012 self.product_ID = 16
1013 else:
1014 self.chip = 1
1015 self.product_ID = 48
1016 except:
1017 retry = retry + 1
1018 else:
1019 raise Exception("i2c read/write error!")
1020
1021# Magnetic
1022if 48 in i2c.scan():
1023 magnetic = Magnetic()
1024else:
1025 print("magnetic init error!")
1026
1027class BME280(object):
1028 def __init__(self):
1029 self.addr = 119
1030 # The “ctrl_hum” register sets the humidity data acquisition options of the device
1031 # 0x01 = [2:0]oversampling ×1
1032 i2c.writeto(self.addr, b'\xF2\x01')
1033 # The “ctrl_meas” register sets the pressure and temperature data acquisition options of the device.
1034 # The register needs to be written after changing “ctrl_hum” for the changes to become effective.
1035 # 0x27 = [7:5]Pressure oversampling ×1 | [4:2]Temperature oversampling ×4 | [1:0]Normal mode
1036 i2c.writeto(self.addr, b'\xF4\x27')
1037 # The “config” register sets the rate, filter and interface options of the device. Writes to the “config”
1038 # register in normal mode may be ignored. In sleep mode writes are not ignored.
1039 i2c.writeto(self.addr, b'\xF5\x00')
1040
1041 i2c.writeto(self.addr, b'\x88', False)
1042 bytes = i2c.readfrom(self.addr, 6)
1043 self.dig_T = ustruct.unpack('Hhh', bytes)
1044
1045 i2c.writeto(self.addr, b'\x8E', False)
1046 bytes = i2c.readfrom(self.addr, 18)
1047 self.dig_P = ustruct.unpack('Hhhhhhhhh', bytes)
1048
1049 i2c.writeto(self.addr, b'\xA1', False)
1050 self.dig_H = array.array('h', [0, 0, 0, 0, 0, 0])
1051 self.dig_H[0] = i2c.readfrom(self.addr, 1)[0]
1052 i2c.writeto(self.addr, b'\xE1', False)
1053 buff = i2c.readfrom(self.addr, 7)
1054 self.dig_H[1] = ustruct.unpack('h', buff[0:2])[0]
1055 self.dig_H[2] = buff[2]
1056 self.dig_H[3] = (buff[3] << 4) | (buff[4] & 0x0F)
1057 self.dig_H[4] = (buff[5] << 4) | (buff[4] >> 4 & 0x0F)
1058 self.dig_H[5] = buff[6]
1059
1060 def temperature(self):
1061 retry = 0
1062 if (retry < 5):
1063 try:
1064 i2c.writeto(self.addr, b'\xFA', False)
1065 buff = i2c.readfrom(self.addr, 3)
1066 T = (((buff[0] << 8) | buff[1]) << 4) | (buff[2] >> 4 & 0x0F)
1067 c1 = (T / 16384.0 - self.dig_T[0] / 1024.0) * self.dig_T[1]
1068 c2 = ((T / 131072.0 - self.dig_T[0] / 8192.0) * (T / 131072.0 - self.dig_T[0] / 8192.0)) * self.dig_T[2]
1069 self.tFine = c1 + c2
1070 return self.tFine / 5120.0
1071 except:
1072 retry = retry + 1
1073 else:
1074 raise Exception("i2c read/write error!")
1075
1076 def pressure(self):
1077 retry = 0
1078 if (retry < 5):
1079 try:
1080 self.temperature()
1081 i2c.writeto(self.addr, b'\xF7', False)
1082 buff = i2c.readfrom(self.addr, 3)
1083 P = (((buff[0] << 8) | buff[1]) << 4) | (buff[2] >> 4 & 0x0F)
1084 c1 = self.tFine / 2.0 - 64000.0
1085 c2 = c1 * c1 * self.dig_P[5] / 32768.0
1086 c2 = c2 + c1 * self.dig_P[4] * 2.0
1087 c2 = c2 / 4.0 + self.dig_P[3] * 65536.0
1088 c1 = (self.dig_P[2] * c1 * c1 / 524288.0 + self.dig_P[1] * c1) / 524288.0
1089 c1 = (1.0 + c1 / 32768.0) * self.dig_P[0]
1090 if c1 == 0.0:
1091 return 0
1092 p = 1048576.0 - P
1093 p = (p - c2 / 4096.0) * 6250.0 / c1
1094 c1 = self.dig_P[8] * p * p / 2147483648.0
1095 c2 = p * self.dig_P[7] / 32768.0
1096 p = p + (c1 + c2 + self.dig_P[6]) / 16.0
1097 return p
1098 except:
1099 retry = retry + 1
1100 else:
1101 raise Exception("i2c read/write error!")
1102
1103 def humidity(self):
1104 retry = 0
1105 if (retry < 5):
1106 try:
1107 self.temperature()
1108 i2c.writeto(self.addr, b'\xFD', False)
1109 buff = i2c.readfrom(self.addr, 2)
1110 H = buff[0] << 8 | buff[1]
1111 h = self.tFine - 76800.0
1112 h = (H - (self.dig_H[3] * 64.0 + self.dig_H[4] / 16384.0 * h)) * \
1113 (self.dig_H[1] / 65536.0 * (1.0 + self.dig_H[5] / 67108864.0 * h * \
1114 (1.0 + self.dig_H[2] / 67108864.0 * h)))
1115 h = h * (1.0 - self.dig_H[0] * h / 524288.0)
1116 if h > 100.0:
1117 return 100.0
1118 elif h < 0.0:
1119 return 0.0
1120 else:
1121 return h
1122 except:
1123 retry = retry + 1
1124 else:
1125 raise Exception("i2c read/write error!")
1126
1127# bm280
1128# if 119 in i2c.scan():
1129# bme280 = BME280()
1130
1131class PinMode(object):
1132 IN = 1
1133 OUT = 2
1134 PWM = 3
1135 ANALOG = 4
1136 OUT_DRAIN = 5
1137
1138
1139pins_remap_esp32 = (33, 32, 35, 34, 39, 0, 16, 17, 26, 25, 36, 2, -1, 18, 19, 21, 5, -1, -1, 22, 23, -1, -1, 27, 14, 12,
1140 13, 15, 4)
1141
1142
1143class MPythonPin():
1144 def __init__(self, pin, mode=PinMode.IN, pull=None):
1145 if mode not in [PinMode.IN, PinMode.OUT, PinMode.PWM, PinMode.ANALOG, PinMode.OUT_DRAIN]:
1146 raise TypeError("mode must be 'IN, OUT, PWM, ANALOG,OUT_DRAIN'")
1147 if pin == 4:
1148 raise TypeError("P4 is used for light sensor")
1149 if pin == 10:
1150 raise TypeError("P10 is used for sound sensor")
1151 try:
1152 self.id = pins_remap_esp32[pin]
1153 except IndexError:
1154 raise IndexError("Out of Pin range")
1155 if mode == PinMode.IN:
1156 # if pin in [3]:
1157 # raise TypeError('IN not supported on P%d' % pin)
1158 self.Pin = Pin(self.id, Pin.IN, pull)
1159 if mode == PinMode.OUT:
1160 if pin in [2, 3]:
1161 raise TypeError('OUT not supported on P%d' % pin)
1162 self.Pin = Pin(self.id, Pin.OUT, pull)
1163 if mode == PinMode.OUT_DRAIN:
1164 if pin in [2, 3]:
1165 raise TypeError('OUT_DRAIN not supported on P%d' % pin)
1166 self.Pin = Pin(self.id, Pin.OPEN_DRAIN, pull)
1167 if mode == PinMode.PWM:
1168 if pin not in [0, 1, 5, 6, 7, 8, 9, 11, 13, 14, 15, 16, 19, 20, 23, 24, 25, 26, 27, 28]:
1169 raise TypeError('PWM not supported on P%d' % pin)
1170 self.pwm = PWM(Pin(self.id), duty=0)
1171 if mode == PinMode.ANALOG:
1172 if pin not in [0, 1, 2, 3, 4, 10]:
1173 raise TypeError('ANALOG not supported on P%d' % pin)
1174 self.adc = ADC(Pin(self.id))
1175 self.adc.atten(ADC.ATTN_11DB)
1176 self.mode = mode
1177
1178 def irq(self, handler=None, trigger=Pin.IRQ_RISING):
1179 if not self.mode == PinMode.IN:
1180 raise TypeError('the pin is not in IN mode')
1181 return self.Pin.irq(handler, trigger)
1182
1183 def read_digital(self):
1184 if not self.mode == PinMode.IN:
1185 raise TypeError('the pin is not in IN mode')
1186 return self.Pin.value()
1187
1188 def write_digital(self, value):
1189 if self.mode not in [PinMode.OUT, PinMode.OUT_DRAIN]:
1190 raise TypeError('the pin is not in OUT or OUT_DRAIN mode')
1191 self.Pin.value(value)
1192
1193 def read_analog(self):
1194 if not self.mode == PinMode.ANALOG:
1195 raise TypeError('the pin is not in ANALOG mode')
1196 return self.adc.read()
1197
1198
1199 def write_analog(self, duty, freq=1000):
1200 if not self.mode == PinMode.PWM:
1201 raise TypeError('the pin is not in PWM mode')
1202 self.pwm.freq(freq)
1203 self.pwm.duty(duty)
1204
1205
1206'''
1207# to be test
1208class LightSensor(ADC):
1209
1210 def __init__(self):
1211 super().__init__(Pin(pins_remap_esp32[4]))
1212 # super().atten(ADC.ATTN_11DB)
1213
1214 def value(self):
1215 # lux * k * Rc = N * 3.9/ 4096
1216 # k = 0.0011mA/Lux
1217 # lux = N * 3.9/ 4096 / Rc / k
1218 return super().read() * 1.1 / 4095 / 6.81 / 0.011
1219
1220'''
1221
1222
1223class wifi:
1224 def __init__(self):
1225 self.sta = network.WLAN(network.STA_IF)
1226 self.ap = network.WLAN(network.AP_IF)
1227
1228 def connectWiFi(self, ssid, passwd, timeout=10):
1229 if self.sta.isconnected():
1230 self.sta.disconnect()
1231 self.sta.active(True)
1232 list = self.sta.scan()
1233 for i, wifi_info in enumerate(list):
1234 try:
1235 if wifi_info[0].decode() == ssid:
1236 self.sta.connect(ssid, passwd)
1237 wifi_dbm = wifi_info[3]
1238 break
1239 except UnicodeError:
1240 self.sta.connect(ssid, passwd)
1241 wifi_dbm = '?'
1242 break
1243 if i == len(list) - 1:
1244 raise OSError("SSID invalid / failed to scan this wifi")
1245 start = time.time()
1246 print("Connection WiFi", end="")
1247 while (self.sta.ifconfig()[0] == '0.0.0.0'):
1248 if time.ticks_diff(time.time(), start) > timeout:
1249 print("")
1250 raise OSError("Timeout!,check your wifi password and keep your network unblocked")
1251 print(".", end="")
1252 time.sleep_ms(500)
1253 print("")
1254 print('WiFi(%s,%sdBm) Connection Successful, Config:%s' % (ssid, str(wifi_dbm), str(self.sta.ifconfig())))
1255
1256 def disconnectWiFi(self):
1257 if self.sta.isconnected():
1258 self.sta.disconnect()
1259 self.sta.active(False)
1260 print('disconnect WiFi...')
1261
1262 def enable_APWiFi(self, essid, password=b'',channel=10):
1263 self.ap.active(True)
1264 if password:
1265 authmode=4
1266 else:
1267 authmode=0
1268 self.ap.config(essid=essid,password=password,authmode=authmode, channel=channel)
1269
1270 def disable_APWiFi(self):
1271 self.ap.active(False)
1272 print('disable AP WiFi...')
1273
1274
1275# 3 rgb leds
1276try:
1277 rgb = NeoPixel(Pin(17, Pin.OUT), 3, 3, 1, brightness=0.3)
1278except Exception: # autodoc 兼容:无硬件环境降级为 None
1279 rgb = None
1280rgb.write()
1281
1282# light sensor
1283try:
1284 light = ADC(Pin(39))
1285except Exception: # autodoc 兼容:无硬件环境降级为 None
1286 light = None
1287light.atten(light.ATTN_11DB)
1288
1289# sound sensor
1290try:
1291 sound = ADC(Pin(36))
1292except Exception: # autodoc 兼容:无硬件环境降级为 None
1293 sound = None
1294sound.atten(sound.ATTN_11DB)
1295
1296# buttons
1297class Button:
1298 def __init__(self, pin_num, reverse=False):
1299 self.__reverse = reverse
1300 (self.__press_level, self.__release_level) = (0, 1) if not self.__reverse else (1, 0)
1301 self.__pin = Pin(pin_num, Pin.IN, pull=Pin.PULL_UP)
1302 self.__pin.irq(trigger=Pin.IRQ_FALLING | Pin.IRQ_RISING, handler=self.__irq_handler)
1303 # self.__user_irq = None
1304 self.event_pressed = None
1305 self.event_released = None
1306 self.__pressed_count = 0
1307 self.__was_pressed = False
1308 # print("level: pressed is {}, released is {}." .format(self.__press_level, self.__release_level))
1309
1310
1311 def __irq_handler(self, pin):
1312 irq_falling = True if pin.value() == self.__press_level else False
1313 # debounce
1314 time.sleep_ms(10)
1315 if self.__pin.value() == (self.__press_level if irq_falling else self.__release_level):
1316 # new event handler
1317 # pressed event
1318 if irq_falling:
1319 if self.event_pressed is not None:
1320 schedule(self.event_pressed, self.__pin)
1321 # key status
1322 self.__was_pressed = True
1323 if (self.__pressed_count < 100):
1324 self.__pressed_count = self.__pressed_count + 1
1325 # release event
1326 else:
1327 if self.event_released is not None:
1328 schedule(self.event_released, self.__pin)
1329
1330
1331 def is_pressed(self):
1332 if self.__pin.value() == self.__press_level:
1333 return True
1334 else:
1335 return False
1336
1337 def was_pressed(self):
1338 r = self.__was_pressed
1339 self.__was_pressed = False
1340 return r
1341
1342 def get_presses(self):
1343 r = self.__pressed_count
1344 self.__pressed_count = 0
1345 return r
1346
1347 def value(self):
1348 return self.__pin.value()
1349
1350 def status(self):
1351 val = self.__pin.value()
1352 if(val==0):
1353 return 1
1354 elif(val==1):
1355 return 0
1356
1357 def irq(self, *args, **kws):
1358 self.__pin.irq(*args, **kws)
1359
1360
1361
1362class Touch:
1363
1364 def __init__(self, pin):
1365 self.__touch_pad = TouchPad(pin)
1366 self.__touch_pad.irq(self.__irq_handler)
1367 self.event_pressed = None
1368 self.event_released = None
1369 self.__pressed_count = 0
1370 self.__was_pressed = False
1371 self.__value = 0
1372
1373 def __irq_handler(self, value):
1374 # when pressed
1375 if value == 1:
1376 if self.event_pressed is not None:
1377 self.event_pressed(value)
1378 self.__was_pressed = True
1379 self.__value = 1
1380 if (self.__pressed_count < 100):
1381 self.__pressed_count = self.__pressed_count + 1
1382 # when released
1383 else:
1384 self.__value = 0
1385 if self.event_released is not None:
1386 self.event_released(value)
1387
1388 def config(self, threshold):
1389 self.__touch_pad.config(threshold)
1390
1391 def is_pressed(self):
1392 if self.__value:
1393 return True
1394 else:
1395 return False
1396
1397 def was_pressed(self):
1398 r = self.__was_pressed
1399 self.__was_pressed = False
1400 return r
1401
1402 def get_presses(self):
1403 r = self.__pressed_count
1404 self.__pressed_count = 0
1405 return r
1406
1407 def read(self):
1408 return self.__touch_pad.read()
1409
1410
1411# button_a = Pin(0, Pin.IN, Pin.PULL_UP)
1412# button_b = Pin(2, Pin.IN, Pin.PULL_UP)
1413try:
1414 button_a = Button(0)
1415except Exception: # autodoc 兼容:无硬件环境降级为 None
1416 button_a = None
1417try:
1418 button_b = Button(2)
1419except Exception: # autodoc 兼容:无硬件环境降级为 None
1420 button_b = None
1421
1422
1423# touchpad
1424touchpad_p = touchPad_P = Touch(Pin(27))
1425touchpad_y = touchPad_Y = Touch(Pin(14))
1426touchpad_t = touchPad_T = Touch(Pin(12))
1427touchpad_h = touchPad_H = Touch(Pin(13))
1428touchpad_o = touchPad_O = Touch(Pin(15))
1429touchpad_n = touchPad_N = Touch(Pin(4))
1430
1431from gui import *
1432
1433
1434def numberMap(inputNum, bMin, bMax, cMin, cMax):
1435 outputNum = 0
1436 outputNum = ((cMax - cMin) / (bMax - bMin)) * (inputNum - bMin) + cMin
1437 return outputNum
1438
1439
1440"""
1441uuid
1442"""
1443def uuid():
1444 uuid = ''
1445 try:
1446 uuid = ubinascii.hexlify(machine.unique_id_custom()).decode().upper()
1447 except Exception as e:
1448 uuid = ubinascii.hexlify(machine.unique_id()).decode().upper()
1449
1450 if(uuid=='ffffffffffff'.upper()):
1451 uuid = ubinascii.hexlify(machine.unique_id()).decode().upper()
1452
1453 return uuid