mpython.py源码

mpython.py源码下载

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