├── .gitignore
├── .gitmodules
├── LICENSE
├── Makefile
├── README.md
├── docs
└── images
│ ├── favicon.ico
│ ├── hcsr04.jpg
│ ├── hcsr04.png
│ ├── micropython.png
│ ├── mpython_ico_en.png
│ ├── parrot.png
│ ├── 掌控-立1.png
│ ├── 掌控-立2.png
│ ├── 透视正面.png
│ └── 透视背面.png
├── library
├── README.md
├── bigiot
│ ├── .gitignore
│ ├── LICENSE
│ ├── MANIFEST
│ ├── MANIFEST.in
│ ├── README.md
│ ├── bigiot.py
│ ├── examples
│ │ └── bigiot_example.py
│ ├── optimize_upip.py
│ ├── sdist_upip.py
│ ├── setup.cfg
│ └── setup.py
├── ir_remote
│ └── ir_remote.py
├── ledstrip
│ ├── LICENSE
│ ├── MANIFEST
│ ├── README.md
│ ├── examples
│ │ └── ledstrip_simple.py
│ ├── ledstrip.py
│ ├── optimize_upip.py
│ ├── sdist_upip.py
│ ├── setup.cfg
│ └── setup.py
├── microbit
│ ├── README.md
│ └── microbit.py
├── qqai
│ ├── README.md
│ ├── __init__.py
│ ├── aai.py
│ ├── base.py
│ ├── nlp.py
│ └── vision
│ │ ├── __init__.py
│ │ ├── face.py
│ │ ├── ocr.py
│ │ └── picture.py
├── urllib
│ ├── README.md
│ └── parse.py
└── yeelight
│ ├── LICENSE
│ ├── MANIFEST
│ ├── MANIFEST.in
│ ├── README.md
│ ├── examples
│ └── yeelight_simple.py
│ ├── images
│ ├── mpython.png
│ └── yeelight.png
│ ├── optimize_upip.py
│ ├── sdist_upip.py
│ ├── setup.cfg
│ ├── setup.py
│ └── yeelight.py
├── mkdocs.yml
├── optimize_upip.py
└── sdist_upip.py
/.gitignore:
--------------------------------------------------------------------------------
1 | __pycache__/
2 | .vscode/
3 | !.gitkeep
4 | site/
5 | docs/index.md
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "library/hcsr04"]
2 | path = library/hcsr04
3 | url = https://github.com/tangliufeng/micropython-hcsr04.git
4 | [submodule "library/ivPID"]
5 | path = library/ivPID
6 | url = https://github.com/tangliufeng/ivPID.git
7 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 labplus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | BASEDIR=$(CURDIR)
2 | DOCDIR=$(BASEDIR)/docs
3 |
4 | install:
5 | pip install mkdocs mkdocs-material
6 |
7 | link:
8 | ln -sf $(BASEDIR)/README.md $(DOCDIR)/index.md
9 |
10 | serve:
11 | $(MAKE) link
12 | mkdocs serve
13 |
14 | deploy:
15 | $(MAKE) link
16 | mkdocs gh-deploy --clean
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # mPython 精选资源
2 |
3 | 
4 |
5 | 设立[aswsome-mpython](https://labplus-cn.github.io/awesome-mpython/)网页项目初衷,旨在收集、归纳掌控板和MicroPython的一些网络上的资源。提供学习指南,库,软件和资源供掌控板和MicroPython爱好者学习!
6 |
7 | `mPython`是`MicroPython`基础上的分支,旨在简化低成本微控制器上的实验和教学。它不需要预先安装Python环境或桌面软件,因此比以往更加轻松地上手。使用`mPython`,您可以编写简洁的Python代码来控制硬件,而不必使用复杂的底层语言(例如C或C ++)(Arduino用于编程的语言)。对初学者来说很棒!
8 |
9 |
10 | ## 精选驱动库
11 |
12 | ### 说明
13 |
14 |
15 |
16 | - 由于MicroPython与mPython会存在细微区别,并不一定完全能在mPython上运行。同时我们也会标识出哪些驱动可在mPython上正常运行。
17 | - 对应一些需要二次修改才能使用的驱动或经典的驱动,我们将会收收纳至[awesome-mpython/library](https://github.com/labplus-cn/awesome-mpython/tree/master/library)。
18 |
19 | 图标说明:
20 |
21 | -
: 经验证可在掌控板上正常使用
22 | -
: 收纳入awesome-mpython/library
23 |
24 |
25 | ### 传感器
26 |
27 |
28 | * [ADXL345-with-Pyboard](https://github.com/AbhinayBandaru/ADXL345-with-Pyboard) - ADXL345 16g 3轴加速度计
29 | * [adxl345_micropython](https://github.com/fanday/adxl345_micropython) - ADXL345 16g 3轴加速度计
30 | * [micropython-lis2hh12](https://github.com/tuupola/micropython-lis2hh12) - LIS2HH12 3轴加速度计
31 | * [MMA7660](https://github.com/Bucknalla/MicroPython-3-Axis-Accelerometer/blob/master/MMA7660.py) - MMA7660 1.5g 3轴加速度计
32 |
33 | * [CCS811](https://github.com/Ledbelly2142/CCS811) - CCS811 空气质量传感器
34 | * [upython-aq-monitor](https://github.com/ayoy/upython-aq-monitor) - PMS5003 颗粒物浓度传感器
35 | * [micropython-bme280](https://github.com/kevbu/micropython-bme280) - Bosch BME280 气象传感器(温度/湿度/气压)
36 | * [mpy_bme280_esp8266](https://github.com/catdog2/mpy_bme280_esp8266) - Bosch BME280 气象传感器(温度/湿度/气压)
37 | * [wipy_bme280](https://bitbucket.org/oscarBravo/wipy_bme280) - Bosch BME280 气象传感器(温度/湿度/气压)
38 | * [micropython-bmp180](https://github.com/micropython-IMU/micropython-bmp180) - Bosch BMP180 气象传感器(温度/气压/海拔)
39 | * [micropython-ov2640](https://github.com/namato/micropython-ov2640) - MicroPython class for OV2640 camera.
40 | * [micropython-esp8266-hmc5883l](https://github.com/gvalkov/micropython-esp8266-hmc5883l) - 3轴数字指南针
41 | * [pyb_ina219](https://github.com/chrisb2/pyb_ina219) - INA219 电压/电流传感器
42 | * [micropython-gp2y0e03](https://bitbucket.org/thesheep/micropython-gp2y0e03) - Sharp GP2Y0E03 红外测距传感器
43 | * [micropython-vl53l0x](https://bitbucket.org/thesheep/micropython-vl53l0x) - VL53L0X Time-of-Flight 激光测距模块
44 | * [micropython-vl6180](https://bitbucket.org/thesheep/micropython-vl6180) - vl6180近距离感测器(光学测距/环境光线)
45 | * [micropython-hcsr04](https://github.com/rsc1975/micropython-hcsr04) - HC-SR04/05 超声波测距
46 | * [ATM90E26_Micropython](https://github.com/whatnick/ATM90E26_Micropython) -ATM90E26 功率测量
47 | * [micropython-MQ](https://github.com/kartun83/micropython-MQ) - MQ系列烟雾传感器
48 | * [MQ135](https://github.com/rubfi/MQ135) - MQ135 烟雾传感器
49 | * [MicroPython-SI1145](https://github.com/neliogodoi/MicroPython-SI1145) - SI1145 光线传感器(紫外光/可见光/红外光)
50 | * [micropython-tsl2561](https://github.com/kfricke/micropython-tsl2561) - TSL2561 数字光强传感器
51 | * [mpy_bh1750fvi_esp8266](https://github.com/catdog2/mpy_bh1750fvi_esp8266) - BH1750FVI 数字光强传感器
52 | * [micropython-bmx055](https://github.com/micropython-IMU/micropython-bmx055) - Driver for Bosch BMX055 IMU sensor.
53 | * [micropython-bno055](https://github.com/deshipu/micropython-bno055) - Bosch Sensortec BNO055 9DOF IMU sensor, I2C interface.
54 | * [micropython-lsm9ds0](https://github.com/micropython-IMU/micropython-lsm9ds0) - LSM9DS0 g-force linear acceleration, gauss magnetic and dps angular rate sensors.
55 | * [micropython-mpu9250](https://github.com/tuupola/micropython-mpu9250) - I2C driver for MPU9250 9-axis motion tracking device.
56 | * [micropython-mpu9x50](https://github.com/micropython-IMU/micropython-mpu9x50) - Driver for the InvenSense MPU9250 inertial measurement unit.
57 | * [MPU6050-ESP8266-MicroPython](https://github.com/adamjezek98/MPU6050-ESP8266-MicroPython) - ESP8266 driver for MPU6050 accelerometer/gyroscope.
58 | * [py-mpu6050](https://github.com/larsks/py-mpu6050) - ESP8266 driver for MPU6050 accelerometer/gyroscope.
59 |
60 | * [micropython-chirp](https://github.com/robberwick/micropython-chirp) - Driver for the Chirp Soil Moisture Sensor.
61 | * [micropython-max31855](https://bitbucket.org/thesheep/micropython-max31855) - Thermocouple amplifier, SPI interface.
62 | * [max31856](https://github.com/alinbaltaru/max31856) - Precision thermocouple to digital converter with linearization, SPI interface.
63 | * [bme680-mqtt-micropython](https://github.com/robmarkcole/bme680-mqtt-micropython) - Driver for BME680 gas, pressure, temperature and humidity sensor.
64 | * [LM75-MicroPython](https://github.com/OldhamMade/LM75-MicroPython) - Driver for LM75 digital temperature sensor, I2C interface.
65 | * [micropython-am2320](https://github.com/mcauser/micropython-am2320) - Aosong AM2320 temperature and humidity sensor, I2C interface.
66 | * [micropython-dht12](https://github.com/mcauser/micropython-dht12) - Aosong DHT12 temperature and humidity sensor, I2C interface.
67 | * [micropython-hdc1008](https://github.com/kfricke/micropython-hdc1008) - Driver for the Texas Instruments HDC1008 humidity and temperature sensor.
68 | * [micropython-mcp9808](https://github.com/kfricke/micropython-mcp9808) - Driver for the Microchip MCP9808 temperature sensor.
69 | * [micropython-mpl115a2](https://github.com/khoulihan/micropython-mpl115a2) - Pyboard driver for the MPL115A2 barometric pressure sensor.
70 | * [micropython-sht30](https://github.com/rsc1975/micropython-sht30) - Driver for SHT30 temperature and humidity sensor.
71 | * [micropython-sht31](https://github.com/kfricke/micropython-sht31) - Driver for the SHT31 temperature and humidity sensor.
72 | * [micropython-Si7005](https://github.com/Smrtokvitek/micropython-Si7005) - Driver for Si7005 relative humidity and temperature sensor.
73 | * [micropython-si7021](https://bitbucket.org/thesheep/micropython-si7021) - SI7021 Temperature and humidity sensor, I2C interface.
74 | * [micropython-si7021](https://github.com/chrisbalmer/micropython-si7021) - SI7021 Temperature and humidity sensor, I2C interface.
75 | * [micropython-Si705x](https://github.com/billyrayvalentine/micropython-Si705x) - Silicon Labs Si705x series of temperature sensors, I2C interface.
76 | * [micropython-Si70xx](https://github.com/billyrayvalentine/micropython-Si70xx) - Silicon Labs Si70xx series of relative humidity and temperature sensors, I2C interface.
77 | * [micropython-tmp102](https://github.com/khoulihan/micropython-tmp102) - Driver for TMP102 digital temperature sensor.
78 | * [SHT10_uPython](https://github.com/Omgitskillah/SHT10_uPython) - Driver for SHT10 temperature and humidity sensor.
79 | * [sht25-micropython](https://github.com/Miceuz/sht25-micropython) - Driver for SHT25 temperature and humidity sensor.
80 | * [micropython-mlx90614](https://github.com/mcauser/micropython-mlx90614) - Driver for Melexis MLX90614 IR temperature sensor.
81 | * [micropython-mpr121](https://github.com/mcauser/micropython-mpr121) - Driver for MPR121 capacitive touch keypads and breakout boards.
82 | * [micropython-ttp223](https://github.com/mcauser/micropython-ttp223) - Examples using TTP223 capacitive touch module.
83 | * [XPT2046-touch-pad-driver-for-PyBoard](https://github.com/robert-hh/XPT2046-touch-pad-driver-for-PyBoard) - Driver for XPT2046 touch pad controller used in many TFT modules.
84 | * [micropython-nunchuck](https://github.com/kfricke/micropython-nunchuck) - Driver for Nunchuk game controller, I2C interface.
85 |
86 | ### 输出类
87 |
88 | * [micropython-adafruit-pca9685](https://github.com/adafruit/micropython-adafruit-pca9685) - 16-channel 12-bit PWM/servo driver.
89 | * [micropython-pca9685](https://bitbucket.org/thesheep/micropython-pca9685) - 16-channel 12-bit PWM/servo driver.
90 | * [L298N](https://github.com/GuyCarver/MicroPython/blob/master/lib/L298N.py) - Driver for the L298N dual h-bridge motor controller.
91 | * [micropython-upybbot](https://github.com/jeffmer/micropython-upybbot) - A4988 driver for bipolar stepper motors.
92 | * [JQ6500](https://github.com/rdagger/micropython-jq6500) - JQ6500 UART MP3 模块的驱动
93 | * [KT403A-MP3](https://github.com/jczic/KT403A-MP3) - Driver for KT403A, used by DFPlayer Mini and Grove MP3 v2.0.
94 | * [micropython-buzzer](https://github.com/fruch/micropython-buzzer) - Play nokia compose and mid files on buzzers.
95 | * [micropython-dfplayer](https://github.com/ShrimpingIt/micropython-dfplayer) - Driver for DFPlayer Mini using UART.
96 | * [micropython-longwave](https://github.com/MattMatic/micropython-longwave) - WAV player for MicroPython board.
97 |
98 |
99 | ### 显示类
100 |
101 |
102 | * LCD
103 |
104 | * [micropython-epaper](https://github.com/peterhinch/micropython-epaper) - Pyboard driver for Embedded Artists 2.7 inch e-paper display.
105 | * [micropython-ili9341](https://bitbucket.org/thesheep/micropython-ili9341) - SSD1606 active matrix epaper display 128x180.
106 | * [micropython-waveshare-epaper](https://github.com/mcauser/micropython-waveshare-epaper) - Drivers for various Waveshare e-paper modules.
107 |
108 | * [Grove_RGB_LCD](https://github.com/dda/MicroPython/blob/master/Grove_RGB_LCD.py) - Driver for SeeedStudio's Grove RGB LCD.
109 | * [lcdi2c](https://github.com/slothyrulez/lcdi2c) - Driver for HD44780 compatible dot matrix LCDs.
110 | * [micropython-charlcd](https://github.com/rdagger/micropython-charlcd) - Driver for HD44780 compatible LCDs.
111 | * [micropython-i2c-lcd](https://github.com/Bucknalla/micropython-i2c-lcd) - Driver for I2C 2x16 LCD Screens.
112 | * [micropython_grove_rgb_lcd_driver](https://github.com/KidVizious/micropython_grove_rgb_lcd_driver) - Driver for SeeedStudio's Grove RGB LCD.
113 | * [pyboard-LCD-character-display](https://github.com/scitoast/pyboard-LCD-character-display) - PyBoard driver for HDD44780 compatible 1602 LCDs.
114 | * [python_lcd](https://github.com/dhylands/python_lcd) - Driver for HD44780 compatible dot matrix LCDs.
115 |
116 | * [micropython-lcd-AQM1248A](https://github.com/forester3/micropython-lcd-AQM1248A) - ESP8266 driver for AQM1248A graphic LCD.
117 | * [micropython-lcd160cr-gui](https://github.com/peterhinch/micropython-lcd160cr-gui) - Simple touch driven event based GUI for the Pyboard and LCD160CR colour display.
118 | * [micropython-pcd8544](https://github.com/mcauser/micropython-pcd8544) - Driver for Nokia 5110 PCD8544 84x48 LCD modules.
119 | * [micropython-st7565](https://github.com/nquest/micropython-st7565) - Driver for ST7565 128x64 LCDs.
120 | * [micropython-st7920](https://github.com/ShrimpingIt/micropython-st7920) - Library for simple graphic primitives on ST7920 128x64 monochrome LCD panel using ESP8266 and SPI.
121 | * [MicroPython_PCD8544](https://github.com/AnthonyKNorman/MicroPython_PCD8544) - ESP8266 driver for Nokia 5110 PCD8544.
122 | * [Official LCD160CR](https://github.com/micropython/micropython/tree/master/drivers/display) - Driver for official MicroPython LCD160CR display with resistive touch sensor.
123 |
124 |
125 | * [micropython-ili9341](https://bitbucket.org/thesheep/micropython-ili9341) - Collection of drivers for TFT displays, ILI9341, SH1106, SSD1606, ST7735.
126 | * [micropython-ili934x](https://github.com/tuupola/micropython-ili934x) - SPI driver for ILI934X series based TFT / LCD displays.
127 | * [MicroPython-ST7735](https://github.com/boochow/MicroPython-ST7735) - ESP32 version of GuyCarvers's ST7735 TFT LCD driver.
128 | * [micropython-st7735](https://github.com/hosaka/micropython-st7735) - Driver for ST7735 TFT LCDs.
129 | * [MicroPython_ST7735](https://github.com/AnthonyKNorman/MicroPython_ST7735) - Driver for ST7735 128x128 TFT.
130 | * [SSD1963-TFT-Library-for-PyBoard](https://github.com/robert-hh/SSD1963-TFT-Library-for-PyBoard) - Driver for SSD1963 864x480 TFT LCDs.
131 | * [ST7735](https://github.com/GuyCarver/MicroPython/blob/master/lib/ST7735.py) - Driver for ST7735 TFT LCDs.
132 |
133 |
134 | * led matrix
135 |
136 | * [micropython-ht1632c](https://github.com/vrialland/micropython-ht1632c) - Driver for HT1632C 32x16 bicolor led matrix.
137 | * [micropython-matrix8x8](https://github.com/JanBednarik/micropython-matrix8x8) - Driver for AdaFruit 8x8 LED Matrix display with HT16K33 backpack.
138 | * [micropython-max7219](https://github.com/mcauser/micropython-max7219) - Driver for MAX7219 8x8 LED matrix modules.
139 | * [micropython-wemos-led-matrix-shield](https://github.com/mactijn/micropython-wemos-led-matrix-shield) - Driver for Wemos D1 Mini Matrix LED shield, using TM1640 chip.
140 | * [micropython-wemos-led-matrix](https://github.com/mattytrentini/micropython-wemos-led-matrix) - Driver for Wemos D1 Mini Matrix LED shield, using TM1640 chip.
141 |
142 |
143 | * 数码管
144 | * [LKM1638](https://github.com/arikb/LKM1638) - Driver for JY-LKM1638 displays based on TM1638 controller.
145 | * [max7219_8digit](https://github.com/pdwerryhouse/max7219_8digit) - Driver for MAX7219 8-digit 7-segment LED modules.
146 | * [micropython-max7219](https://github.com/JulienBacquart/micropython-max7219) - Driver for MAX7219 8-digit 7-segment LED modules.
147 | * [micropython-my9221](https://github.com/mcauser/micropython-my9221) - Driver for MY9221 10-segment LED bar graph modules.
148 | * [micropython-tm1637](https://github.com/mcauser/micropython-tm1637) - Driver for TM1637 quad 7-segment LED modules.
149 | * [micropython-tm1638](https://github.com/mcauser/micropython-tm1638) - Driver for TM1638 dual quad 7-segment LED modules with switches.
150 | * [micropython-tm1640](https://github.com/mcauser/micropython-tm1640) - Driver for TM1740 8x8 LED matrix modules.
151 |
152 | * 灯带
153 | * [micropython-morsecode](https://github.com/mampersat/micropython-morsecode) - Blink an LED with morse coded message.
154 | * [micropython-p9813](https://github.com/mcauser/micropython-p9813) - Driver for P9813 RGB LED used in SeeedStudio's Grove Chainable RGB LED.
155 | * [micropython-ws2812-7seg](https://github.com/HubertD/micropython-ws2812-7seg) - 7-segment display using WS2812 RGB LEDs.
156 | * [micropython-ws2812](https://github.com/JanBednarik/micropython-ws2812) - Driver for WS2812 RGB LEDs.
157 | * [Official APA102](http://docs.micropython.org/en/latest/esp8266/quickref.html#apa102-driver) - ESP8266 APA102/DotStar RGB LED driver.
158 | * [Official WS2811](http://docs.micropython.org/en/latest/esp8266/quickref.html#neopixel-driver) - ESP8266 WS2811/NeoPixel RGB LED driver.
159 | * [tlc5940-micropython](https://github.com/oysols/tlc5940-micropython) - Driver for TLC5940 16 channel LED driver.
160 | * [ledstrip](https://github.com/labplus-cn/awesome-mpython/tree/master/library/ledstrip) - micropython neopixel module的增强版.
161 |
162 | * OLED
163 | * [Grove_OLED](https://github.com/dda/MicroPython/blob/master/Grove_OLED.py) - Driver for SSD1327 used by SeeedStudio's Grove OLED Display 1.12" v1.0.
164 | * [micropython-oled](https://bitbucket.org/thesheep/micropython-oled) - Collection of drivers for monochrome OLED displays, PCD8544, SH1106, SSD1306, UC1701X.
165 | * [micropython-ssd1327](https://github.com/mcauser/micropython-ssd1327) - Driver for SSD1327 128x128 4-bit greyscale OLED displays.
166 | * [micropython-ssd1351](https://github.com/rdagger/micropython-ssd1351) - Driver for SSD1351 OLED displays.
167 | * [MicroPython_SSD1306](https://github.com/AnthonyKNorman/MicroPython_SSD1306) - ESP8266 driver for SSD1306 OLED 128x64 displays.
168 | * [Official SSD1306](https://github.com/micropython/micropython/tree/master/drivers/display) - Driver for SSD1306 128x64 OLED displays.
169 | * [SH1106](https://github.com/robert-hh/SH1106) -
170 |
171 | ### 通讯类
172 |
173 |
174 | * [PyBoard-HC05-Android](https://github.com/KipCrossing/PyBoard-HC05-Android) - Pyboard HC05 Bluetooth adaptor example application.
175 | * [Official wiznet5k](https://github.com/micropython/micropython/tree/master/drivers/wiznet5k) - Official driver for the WIZnet5x00 series of Ethernet controllers.
176 | * [micropyGPS](https://github.com/inmcm/micropyGPS) - Full featured GPS NMEA sentence parser.
177 | * [micropython-gnssl76l](https://github.com/tuupola/micropython-gnssl76l) - MicroPython I2C driver for Quectel GNSS L76-L (GPS).
178 |
179 |
180 | * 红外
181 | * [micropython-necir](https://github.com/MattMatic/micropython-necir) - NEC infrared capture for TL1838 IR receiver LEDs.
182 | * [Micropython-IR](https://github.com/designerPing/Micropython-IR) - Pyboard infrared remote sniff and replay.
183 | * [IR Remote](https://github.com/labplus-cn/awesome-mpython/tree/master/library/ir_remote) - 红外编解码(NEC)的驱动
184 |
185 |
186 |
187 | * [Official OneWire](https://github.com/micropython/micropython/tree/master/drivers/onewire) - For devices using the OneWire bus, eg Dallas ds18x20.
188 |
189 |
190 | * [micropython-radio](https://github.com/peterhinch/micropython-radio) - Protocols for nRF24L01 2.4Ghz radio modules.
191 | * [micropython-rfsocket](https://github.com/wuub/micropython-rfsocket) - Micropython implementation of popular 433MHzn based RFSockets.
192 | * [Official nRF24L01](https://github.com/micropython/micropython/tree/master/drivers/nrf24l01) - Official driver for nRF24L01 2.4Ghz radio modules.
193 |
194 | * [micropython-mfrc522](https://github.com/wendlers/micropython-mfrc522) - Driver for NXP MFRC522 RFID reader/writer.
195 | * [micropython-wiegand](https://github.com/pjz/micropython-wiegand) - Wiegand protocol reader.
196 |
197 | * [micropython-tinyrtc-i2c](https://github.com/mcauser/micropython-tinyrtc-i2c) - Driver for DS1307 RTC and AT24C32N EEPROM.
198 | * [Micropython_TinyRTC](https://github.com/AnthonyKNorman/Micropython_TinyRTC) - Driver for DS1307 RTC.
199 |
200 | * [HueBridge](https://github.com/FRC4564/HueBridge) - Philips Hue Bridge.
201 |
202 | ### 功能类
203 |
204 |
205 | * [ads1x15](https://github.com/robert-hh/ads1x15) - Driver for the ADS1015/ADS1115 ADC, I2C interface.
206 | * [micropython-ads1015](https://bitbucket.org/thesheep/micropython-ads1015) - ADS1015 12-Bit and ADS1115 16-bit ADC, 4 channels with programmable gain, I2C interface.
207 | * [Micropython_ADS1115](https://github.com/AnthonyKNorman/Micropython_ADS1115) - ADS1115 16-bit ADC, 4 channels with programmable gain, I2C interface.
208 | * [micropython-mcp4725](https://github.com/wayoda/micropython-mcp4725) - Driver for the MCP4725 I2C DAC.
209 | * [MCP23017-ESP8266-Miniature-Driver](https://github.com/forkachild/MCP23017-ESP8266-Miniature-Driver) - Driver for MCP23017 16-bit I/O Expander.
210 | * [micropython-mcp230xx](https://github.com/ShrimpingIt/micropython-mcp230xx) - Driver for MCP23017 and MCP23008 GPIO expanders.
211 | * [Micropython-AD9833](https://github.com/KipCrossing/Micropython-AD9833) - Pyboard driver for AD9833, spi interface.
212 | * [microbit](https://github.com/labplus-cn/awesome-mpython/tree/master/library/microbit) - 掌控板兼容MicroBit
213 | * [ivPID](https://github.com/labplus-cn/awesome-mpython/tree/master/library/ivPID) - PID控制器
214 |
215 |
216 |
217 |
218 | ### 网络类
219 |
220 | * [urllib.parse](https://github.com/labplus-cn/awesome-mpython/tree/master/library/urllib) - URL编码 (MicroPython-lib@urllib.parse精简版)
221 | * [bigiot](https://github.com/labplus-cn/awesome-mpython/tree/master/library/bigiot) - 贝壳物联
222 | * [yeelight](https://github.com/labplus-cn/awesome-mpython/tree/master/library/yeelight) - YeeLight
223 | * [qqai](https://github.com/labplus-cn/awesome-mpython/tree/master/library/qqai) - [腾讯AI开放平台](https://ai.qq.com/)
224 |
225 |
226 | ------------------------------
227 |
228 | ## 软件
229 |
230 | ## 社区
231 |
232 | ## 贡献
233 |
234 | 始终欢迎您提供意见和建议!请提出请求以修改Awesome mPython。
235 |
236 | - 维护者:[tangliufeng](https://github.com/tangliufeng)
237 | - 共享者:
238 |
239 |
240 | ## 许可证
241 | 由[tangliufeng@LabPlus](https://github.com/tangliufeng)编译和维护。
--------------------------------------------------------------------------------
/docs/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/favicon.ico
--------------------------------------------------------------------------------
/docs/images/hcsr04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/hcsr04.jpg
--------------------------------------------------------------------------------
/docs/images/hcsr04.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/hcsr04.png
--------------------------------------------------------------------------------
/docs/images/micropython.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/micropython.png
--------------------------------------------------------------------------------
/docs/images/mpython_ico_en.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/mpython_ico_en.png
--------------------------------------------------------------------------------
/docs/images/parrot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/parrot.png
--------------------------------------------------------------------------------
/docs/images/掌控-立1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/掌控-立1.png
--------------------------------------------------------------------------------
/docs/images/掌控-立2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/掌控-立2.png
--------------------------------------------------------------------------------
/docs/images/透视正面.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/透视正面.png
--------------------------------------------------------------------------------
/docs/images/透视背面.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/docs/images/透视背面.png
--------------------------------------------------------------------------------
/library/README.md:
--------------------------------------------------------------------------------
1 |
2 | ## Library Management
3 |
4 | 库文件应建立独立文件夹存放,需要说明使用方法,可添加`README`加以说明!
5 |
6 | ## License
7 |
8 | 所有代码均在MIT许可下发布。
--------------------------------------------------------------------------------
/library/bigiot/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | *.egg-info/
--------------------------------------------------------------------------------
/library/bigiot/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 labplus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/library/bigiot/MANIFEST:
--------------------------------------------------------------------------------
1 | # file GENERATED by distutils, do NOT edit
2 | README.md
3 | setup.cfg
4 | setup.py
5 |
--------------------------------------------------------------------------------
/library/bigiot/MANIFEST.in:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/bigiot/MANIFEST.in
--------------------------------------------------------------------------------
/library/bigiot/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## 概述
4 |
5 | 贝壳物联是一个让你与智能设备沟通更方便的物联网云平台,你可以通过互联网以对话、遥控器等形式与你的智能设备聊天、发送指令,查看实时数据,跟实际需求设置报警条件,通过APP、邮件、短信、微博、微信等方式通知用户。
6 |
7 | repo 提供掌控板或micropython连接贝壳物联平台功能,你可以设备与设备间的通讯、上传传感器数据、或者通过web端或微信发送指令给设备。也可以通过智能语音助手(天猫),控制设备。实现语音控制。
8 |
9 | - mPython library GitHub:https://github.com/labplus-cn/mPython-lib
10 | - mPython Library Documentation:https://mpython-lib.readthedocs.io
11 |
12 | ## 库的安装方法
13 |
14 | 可通过以下任一方法进行安装。
15 | 1. 将项目中的`bigiot.py`
16 | 2. 在掌控板REPL界面中,使用upip安装,步骤如下:
17 | * 前置条件需要掌控板连接网络
18 | * 导入upip模块,执行`import upip`
19 | * 执行`upip.install('mPython-bigiot')
20 |
21 | ```python
22 | >>> import upip
23 | >>> upip.install('mPython-bigiot')
24 | ```
25 |
26 |
27 | ## 执照
28 |
29 | 所有代码均在MIT许可下发布。
--------------------------------------------------------------------------------
/library/bigiot/bigiot.py:
--------------------------------------------------------------------------------
1 | """
2 | 贝壳物联是一个让你与智能设备沟通更方便的物联网云平台,你可以通过互联网以对话、遥控器等形式与你的智能设备聊天、发送指令,查看实时数据,
3 | 跟实际需求设置报警条件,通过APP、邮件、短信、微博、微信等方式通知用户。
4 |
5 | | 在使用前,需要先到贝壳物联注册账号,并增加设备 https://www.bigiot.net
6 | | 贝壳物联平台通讯协议:https://www.bigiot.net/help/1.html
7 | """
8 | """
9 | The MIT License (MIT)
10 |
11 | Copyright (c) 2019, labplus@Tangliufeng
12 |
13 | Permission is hereby granted, free of charge, to any person obtaining a copy
14 | of this software and associated documentation files (the "Software"), to deal
15 | in the Software without restriction, including without limitation the rights
16 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 | copies of the Software, and to permit persons to whom the Software is
18 | furnished to do so, subject to the following conditions:
19 |
20 | The above copyright notice and this permission notice shall be included in
21 | all copies or substantial portions of the Software.
22 |
23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 | THE SOFTWARE.
30 | """
31 | import _thread
32 | import socket
33 | import json
34 | import time
35 |
36 | Server_IP = "www.bigiot.net"
37 | Server_Port = 8282
38 |
39 |
40 | class Device:
41 | """
42 | 构建bigiot设备
43 |
44 | :param id(int): 智能设备ID号,类型为整形
45 | :param api_key(str): 智能设备APIKEY,类型为字符串
46 | """
47 |
48 | def __init__(self, id, api_key):
49 | self.ID = str(id)
50 | self.K = api_key
51 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
52 | self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
53 | self.socket.setblocking(True)
54 | self.socket.connect((Server_IP, Server_Port))
55 | _thread.start_new_thread(self._reciver_loop, ())
56 | self.say_cb = None
57 | self.checkinOK = False
58 | self._send_return = None
59 | self.check_out()
60 | for i in range(3):
61 | self.check_in()
62 | if self.checkinOK:
63 | break
64 | time.sleep(1)
65 |
66 | # Send data, and wait for a return
67 |
68 | def _socket_send(self, str):
69 | self._send_return = None
70 | try:
71 | self.socket.send(str)
72 | # print("Send: %s" % str)
73 | except OSError as e:
74 | if e.args[0] == 104:
75 | self.__init__(self.ID, self.K)
76 | self.socket.send(str)
77 | else:
78 | raise e
79 |
80 | def say_callback(self, f):
81 | """
82 | 接收设备通讯的回调函数
83 |
84 | :param f(function): 回调函数,f(msg,id,name)。``msg`` 参数为接收消息, ``id`` 参数为发送设备ID, ``name`` 参数为设备名称。
85 | """
86 | self.say_cb = f
87 |
88 | # Sockets receive data
89 |
90 | def _reciver_loop(self):
91 |
92 | while True:
93 |
94 | res = self.socket.recv(512).decode()
95 |
96 | if len(res) == 0:
97 | continue
98 | dict_res = json.loads(res)
99 | # 应答服务器的心跳包
100 | if dict_res["M"] == 'b':
101 | self.socket.send('{"M":"beat"}\n')
102 | continue
103 | # 服务器连接成功
104 | elif dict_res["M"] == "WELCOME TO BIGIOT":
105 | print("WELCOME TO BIGIOT !")
106 | continue
107 |
108 | self.respon = dict_res
109 | # print(self.respon)
110 |
111 | method = dict_res["M"]
112 |
113 | # check login
114 | if method == "checkinok":
115 | self.checkinOK = True
116 |
117 | if method == "isOL":
118 | self._send_return = dict_res["R"]
119 |
120 | if method == "checked" or method == "connected":
121 | self._send_return = dict_res["M"]
122 |
123 | if method == "time":
124 | self._send_return = dict_res["T"]
125 |
126 | # say 指令
127 | if method == "say" and dict_res["C"] is not None:
128 | msg = (dict_res["C"], dict_res["ID"], dict_res["NAME"])
129 | self.say_cb(msg)
130 |
131 | self.isRecv = True
132 |
133 | def check_in(self):
134 | """
135 | 设备登录
136 | """
137 | obj = {"M": "checkin", "ID": self.ID, "K": self.K}
138 | obj = json.dumps(obj) + "\n"
139 | self._socket_send(obj)
140 |
141 | def check_out(self):
142 | """
143 | 设备下线
144 | """
145 | obj = {"M": "checkout", "ID": self.ID, "K": self.K}
146 | obj = json.dumps(obj) + "\n"
147 | self._socket_send(obj)
148 |
149 | def say(self, user_id=None, group_id=None, device_id=None, msg=None):
150 | """
151 | 设备间的通讯
152 |
153 | :param user_id(int): 用户ID。如你的用户ID为U5600,则user_id=5600。可用于web、微信、app平台间通讯。
154 | :param group_id(int): 群组ID。你可以在平台设置多个设备为一个群组,编译相互通讯。
155 | :param device_id(int): 设备ID。
156 | :param msg(str):发送消息。
157 | """
158 | while True:
159 | if user_id is not None:
160 | ID = "U" + str(user_id)
161 | break
162 | if group_id is not None:
163 | ID = "G" + str(group_id)
164 | break
165 | if device_id is not None:
166 | ID = "D" + str(device_id)
167 | break
168 |
169 | obj = {"M": "say", "ID": ID, "C": msg}
170 | obj = json.dumps(obj) + "\n"
171 | self._socket_send(obj)
172 |
173 | # Submit data to the data interface
174 |
175 | def update(self, id, data):
176 | """
177 | 向接口发送数据。先在平台新增并设置接口。
178 |
179 | :param id(int): 接口ID,类型为整形
180 | :param data(str): 发送数据,类型为字符串,一般用于上传传感器数据。
181 | """
182 | dict_data = {}
183 | dict_data[str(id)] = data
184 | obj = {"M": "update", "ID": self.ID, "V": dict_data}
185 | obj = json.dumps(obj) + "\n"
186 | self._socket_send(obj)
187 |
188 | # Check online
189 |
190 | def is_online(self, device_id):
191 | """
192 | 查询设备是否在线
193 |
194 | :param device_id(int): 你要查询的设备ID
195 | :return: 返回设备状态。0代表不在线,1代表在线
196 | """
197 | self.isRecv = False
198 | obj = {"M": "isOL", "ID": "D" + str(device_id)}
199 | obj = json.dumps(obj) + "\n"
200 | start_time = time.time()
201 | self._socket_send(obj)
202 | while not self.isRecv:
203 | if time.time() - start_time > 2:
204 | return None
205 | return int(self._send_return["D" + str(device_id)])
206 |
207 | def status(self):
208 | """
209 | 查询当前设备状态,两次查询间隔不得小于10s
210 |
211 | :return: connected代表已连接服务器尚未登录,checked代表已连接且登录成功
212 | """
213 | self.isRecv = False
214 | obj = {"M": "status"}
215 | obj = json.dumps(obj) + "\n"
216 | self._socket_send(obj)
217 | start_time = time.time()
218 | while not self.isRecv:
219 | if time.time() - start_time > 1:
220 | return None
221 | return self._send_return
222 |
223 | def time(self, format="stamp"):
224 | """
225 | 查询服务器时间
226 |
227 | :param format(str): stamp(1466659300)、"Y-m-d"(2016-06-21)、Y.m.d(2016.06.21)、Y-m-d H:i:s(2016-06-21 10:25:30)
228 | :return: 返回时间
229 | """
230 | self.isRecv = False
231 | obj = {"M": "time", "F": format}
232 | obj = json.dumps(obj) + "\n"
233 | self._socket_send(obj)
234 | start_time = time.time()
235 | while not self.isRecv:
236 | if time.time() - start_time > 1:
237 | raise bigiotException("Bigiot Server no response ")
238 | return self._send_return
239 |
240 |
241 | # #Send an alert
242 | # def alert(self, C, B):
243 | # obj = {"M": "alert", "C": C, "B": B}
244 | # obj = json.dumps(obj)+"\n"
245 | # self.socket.send(obj)
246 |
247 |
248 |
--------------------------------------------------------------------------------
/library/bigiot/examples/bigiot_example.py:
--------------------------------------------------------------------------------
1 | from mpython import *
2 | from bigiot import Device
3 |
4 | mywifi = wifi() # 连接wifi
5 | mywifi.connectWiFi('', '')
6 |
7 |
8 |
9 | ID = "" # 设备ID
10 | API_KEY = "" # 设备APIKEY
11 |
12 | def say_cb(msg): # 回调函数
13 | print(msg)
14 |
15 | device = Device(ID, API_KEY) # 构建bigiot 设备
16 |
17 | device.say_callback(say_cb) # 设置say通讯的回调函数
18 |
19 | device.check_in() # 登录
20 |
21 | device.say(user_id=0000,msg="hello I am mpython!") # 向web,app端发送消息
22 |
--------------------------------------------------------------------------------
/library/bigiot/optimize_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This script optimizes a Python source distribution tarball as produced by
3 | # "python3 setup.py sdist" command for MicroPython's native package manager,
4 | # upip. Optimization includes:
5 | # * Removing metadata files not used by upip (this includes setup.py)
6 | # * Recompressing gzip archive with 4K dictionary size so it can be
7 | # installed even on low-heap targets.
8 | #
9 | import sys
10 | import os
11 | import zlib
12 | from subprocess import Popen, PIPE
13 | import glob
14 | import tarfile
15 | import re
16 | import io
17 |
18 |
19 | def gzip_4k(inf, fname):
20 | comp = zlib.compressobj(level=9, wbits=16 + 12)
21 | with open(fname + ".out", "wb") as outf:
22 | while 1:
23 | data = inf.read(1024)
24 | if not data:
25 | break
26 | outf.write(comp.compress(data))
27 | outf.write(comp.flush())
28 | os.rename(fname, fname + ".orig")
29 | os.rename(fname + ".out", fname)
30 |
31 |
32 | def recompress(fname):
33 | with Popen(["gzip", "-d", "-c", fname], stdout=PIPE).stdout as inf:
34 | gzip_4k(inf, fname)
35 |
36 | def find_latest(dir):
37 | res = []
38 | for fname in glob.glob(dir + "/*.gz"):
39 | st = os.stat(fname)
40 | res.append((st.st_mtime, fname))
41 | res.sort()
42 | latest = res[-1][1]
43 | return latest
44 |
45 |
46 | def recompress_latest(dir):
47 | latest = find_latest(dir)
48 | print(latest)
49 | recompress(latest)
50 |
51 |
52 | FILTERS = [
53 | # include, exclude, repeat
54 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
55 | (r".+\.py$", r"[^/]+$"),
56 | (None, r".+\.egg-info/.+"),
57 | ]
58 |
59 |
60 | outbuf = io.BytesIO()
61 |
62 | def filter_tar(name):
63 | fin = tarfile.open(name, "r:gz")
64 | fout = tarfile.open(fileobj=outbuf, mode="w")
65 | for info in fin:
66 | # print(info)
67 | if not "/" in info.name:
68 | continue
69 | fname = info.name.split("/", 1)[1]
70 | include = None
71 |
72 | for inc_re, exc_re in FILTERS:
73 | if include is None and inc_re:
74 | if re.match(inc_re, fname):
75 | include = True
76 |
77 | if include is None and exc_re:
78 | if re.match(exc_re, fname):
79 | include = False
80 |
81 | if include is None:
82 | include = True
83 |
84 | if include:
85 | print("Including:", fname)
86 | else:
87 | print("Excluding:", fname)
88 | continue
89 |
90 | farch = fin.extractfile(info)
91 | fout.addfile(info, farch)
92 | fout.close()
93 | fin.close()
94 |
95 |
96 |
97 | from setuptools import Command
98 |
99 | class OptimizeUpip(Command):
100 |
101 | user_options = []
102 |
103 | def run(self):
104 | latest = find_latest("dist")
105 | filter_tar(latest)
106 | outbuf.seek(0)
107 | gzip_4k(outbuf, latest)
108 |
109 | def initialize_options(self):
110 | pass
111 |
112 | def finalize_options(self):
113 | pass
114 |
115 |
116 | # For testing only
117 | if __name__ == "__main__":
118 | # recompress_latest(sys.argv[1])
119 | filter_tar(sys.argv[1])
120 | outbuf.seek(0)
121 | gzip_4k(outbuf, sys.argv[1])
122 |
--------------------------------------------------------------------------------
/library/bigiot/sdist_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This module overrides distutils (also compatible with setuptools) "sdist"
3 | # command to perform pre- and post-processing as required for MicroPython's
4 | # upip package manager.
5 | #
6 | # Preprocessing steps:
7 | # * Creation of Python resource module (R.py) from each top-level package's
8 | # resources.
9 | # Postprocessing steps:
10 | # * Removing metadata files not used by upip (this includes setup.py)
11 | # * Recompressing gzip archive with 4K dictionary size so it can be
12 | # installed even on low-heap targets.
13 | #
14 | import sys
15 | import os
16 | import zlib
17 | from subprocess import Popen, PIPE
18 | import glob
19 | import tarfile
20 | import re
21 | import io
22 |
23 | from distutils.filelist import FileList
24 | from setuptools.command.sdist import sdist as _sdist
25 |
26 |
27 | def gzip_4k(inf, fname):
28 | comp = zlib.compressobj(level=9, wbits=16 + 12)
29 | with open(fname + ".out", "wb") as outf:
30 | while 1:
31 | data = inf.read(1024)
32 | if not data:
33 | break
34 | outf.write(comp.compress(data))
35 | outf.write(comp.flush())
36 | os.rename(fname, fname + ".orig")
37 | os.rename(fname + ".out", fname)
38 |
39 |
40 | FILTERS = [
41 | # include, exclude, repeat
42 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
43 | (r".+\.py$", r"[^/]+$"),
44 | (None, r".+\.egg-info/.+"),
45 | ]
46 |
47 |
48 | outbuf = io.BytesIO()
49 |
50 | def filter_tar(name):
51 | fin = tarfile.open(name, "r:gz")
52 | fout = tarfile.open(fileobj=outbuf, mode="w")
53 | for info in fin:
54 | # print(info)
55 | if not "/" in info.name:
56 | continue
57 | fname = info.name.split("/", 1)[1]
58 | include = None
59 |
60 | for inc_re, exc_re in FILTERS:
61 | if include is None and inc_re:
62 | if re.match(inc_re, fname):
63 | include = True
64 |
65 | if include is None and exc_re:
66 | if re.match(exc_re, fname):
67 | include = False
68 |
69 | if include is None:
70 | include = True
71 |
72 | if include:
73 | print("including:", fname)
74 | else:
75 | print("excluding:", fname)
76 | continue
77 |
78 | farch = fin.extractfile(info)
79 | fout.addfile(info, farch)
80 | fout.close()
81 | fin.close()
82 |
83 |
84 | def make_resource_module(manifest_files):
85 | resources = []
86 | # Any non-python file included in manifest is resource
87 | for fname in manifest_files:
88 | ext = fname.rsplit(".", 1)[1]
89 | if ext != "py":
90 | resources.append(fname)
91 |
92 | if resources:
93 | print("creating resource module R.py")
94 | resources.sort()
95 | last_pkg = None
96 | r_file = None
97 | for fname in resources:
98 | try:
99 | pkg, res_name = fname.split("/", 1)
100 | except ValueError:
101 | print("not treating %s as a resource" % fname)
102 | continue
103 | if last_pkg != pkg:
104 | last_pkg = pkg
105 | if r_file:
106 | r_file.write("}\n")
107 | r_file.close()
108 | r_file = open(pkg + "/R.py", "w")
109 | r_file.write("R = {\n")
110 |
111 | with open(fname, "rb") as f:
112 | r_file.write("%r: %r,\n" % (res_name, f.read()))
113 |
114 | if r_file:
115 | r_file.write("}\n")
116 | r_file.close()
117 |
118 |
119 | class sdist(_sdist):
120 |
121 | def run(self):
122 | self.filelist = FileList()
123 | self.get_file_list()
124 | make_resource_module(self.filelist.files)
125 |
126 | r = super().run()
127 |
128 | assert len(self.archive_files) == 1
129 | print("filtering files and recompressing with 4K dictionary")
130 | filter_tar(self.archive_files[0])
131 | outbuf.seek(0)
132 | gzip_4k(outbuf, self.archive_files[0])
133 |
134 | return r
135 |
136 |
137 | # For testing only
138 | if __name__ == "__main__":
139 | filter_tar(sys.argv[1])
140 | outbuf.seek(0)
141 | gzip_4k(outbuf, sys.argv[1])
142 |
--------------------------------------------------------------------------------
/library/bigiot/setup.cfg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/bigiot/setup.cfg
--------------------------------------------------------------------------------
/library/bigiot/setup.py:
--------------------------------------------------------------------------------
1 | # import sys
2 | # sys.path.pop(0)
3 | # sys.path.append("..")
4 | from setuptools import setup
5 | import sdist_upip
6 | from os import path
7 |
8 | # read the contents of your README file
9 | from os import path
10 | this_directory = path.abspath(path.dirname(__file__))
11 | with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
12 | long_description = f.read()
13 |
14 | VERSION= '0.0.3'
15 |
16 | setup(name='mPython-bigiot',
17 | version=VERSION,
18 | description='bigiot for mPython library',
19 | long_description=long_description,
20 | long_description_content_type="text/markdown",
21 | url='https://github.com/labplus-cn/mPython-lib',
22 | author='tangliufeng@LabPlus',
23 | author_email='137513285@qq.com',
24 | maintainer='LabPlus Developers',
25 | license='MIT',
26 | cmdclass={'sdist': sdist_upip.sdist},
27 | py_modules=['bigiot'],
28 | # packages=['email'],
29 | # install_requires=['']
30 | )
31 |
32 |
--------------------------------------------------------------------------------
/library/ir_remote/ir_remote.py:
--------------------------------------------------------------------------------
1 |
2 | # The MIT License (MIT)
3 |
4 | # Copyright (c) 2019, Tangliufeng for labplus Industries
5 |
6 | # Permission is hereby granted, free of charge, to any person obtaining a copy
7 | # of this software and associated documentation files (the "Software"), to deal
8 | # in the Software without restriction, including without limitation the rights
9 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | # copies of the Software, and to permit persons to whom the Software is
11 | # furnished to do so, subject to the following conditions:
12 |
13 | # The above copyright notice and this permission notice shall be included in
14 | # all copies or substantial portions of the Software.
15 |
16 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | # THE SOFTWARE.
23 |
24 | # NEC infrared receiving and sending library of the mPython or MicropPython, please note that sending and receiving function cannot be used at the same time.
25 | # Both have an effect,only choose one.
26 | #
27 | '''
28 | # IR Receive example:
29 | from ir_remote import IRDecode
30 | from machine import Pin
31 |
32 | def remote_callback(address,command):
33 | print(address,command)
34 |
35 | remote = IRDecode( Pin.P1)
36 | remote.set_callback(remote_callback)
37 | # enable print debug
38 | # remote.set_debug(True)
39 | '''
40 |
41 | '''
42 | # IR send example:
43 | from ir_remote import IRTransmit
44 | from machine import Pin
45 |
46 | ir = IRTransmit(Pin.P0)
47 |
48 | ir.send(0,01) # format (address, command). or ir.send(b'\x00',b'\x01')
49 |
50 | '''
51 |
52 |
53 |
54 | def remote_callback(address,command):
55 | print(address,command)
56 | from machine import Pin, PWM
57 | import time
58 | import _thread
59 | import gc
60 |
61 | class IRDecodeException(Exception):
62 | """Generic decode exception"""
63 | pass
64 |
65 |
66 | class _Const:
67 | NEC_HDR_MARK = 9000
68 | NEC_HDR_SPACE = 4500
69 | NEC_BIT_MARK = 560
70 |
71 | class IRDecode:
72 |
73 |
74 | def __init__(self, pin):
75 |
76 | self.pulse_buffer = []
77 | self._prev_time = 0
78 | self.callback = None
79 | self.debug = False
80 | self.waittime = 150 # time in milliseconds
81 | self.recv = Pin(pin, Pin.IN, Pin.PULL_UP)
82 | self.recv.irq(trigger=Pin.IRQ_RISING | Pin.IRQ_FALLING,
83 | handler=self._pulse_width_record)
84 | _thread.start_new_thread(self._ir_recv_thread, ())
85 |
86 | def _pulse_width_record(self, pin):
87 | """record the width of th IR remote signal."""
88 | self._time = time.ticks_us()
89 | if self._prev_time == 0:
90 | self._prev_time = self._time
91 | return
92 | self.pulse_buffer.append(self._time - self._prev_time)
93 | self._prev_time = self._time
94 |
95 | def _lead_cheak(self):
96 | """function to cheak the lead code """
97 | offset = 0.3
98 | return int(_Const.NEC_HDR_MARK * (1-offset)) < self.pulse_buffer[0] < int(_Const.NEC_HDR_MARK*(1+offset)) \
99 | and int(_Const.NEC_HDR_SPACE*(1-offset)) < self.pulse_buffer[1] < int(_Const.NEC_HDR_SPACE*(1+offset))
100 |
101 | def decode_pulse_nec(self):
102 | """decode IR signal of NEC"""
103 | recv_bytes = bytearray(0)
104 | index = 0
105 | if self._lead_cheak():
106 | for i in range(4):
107 | byte = 0
108 | for j in range(8):
109 | index = 16 * i + 2 * j + 2
110 | _Const.NEC_BIT_MARK = min(
111 | _Const.NEC_BIT_MARK, self.pulse_buffer[index])
112 | if (self.pulse_buffer[index] +
113 | self.pulse_buffer[index + 1]) > _Const.NEC_BIT_MARK * 4:
114 | byte |= 1 << j
115 |
116 | recv_bytes.append(byte)
117 | return bytes(recv_bytes)
118 |
119 | def _print_debug(self,decode):
120 | """"""
121 | print('---------Received pulse width buffer---------')
122 | print('Lead Code: (%d %d)' %
123 | (self.pulse_buffer[0], self.pulse_buffer[1]))
124 | index = 0
125 | for i in range(4):
126 | print('Byte %d:' % i, end='')
127 | for j in range(8):
128 | index = 16 * i + 2 * j + 2
129 | print('(%d %d)' % (self.pulse_buffer[index], self.pulse_buffer[index + 1]),
130 | end=', ')
131 | print('')
132 | print('Buffer:{} ,length:{}' .format(
133 | decode, len(self.pulse_buffer)))
134 | print('--------------------------------------------')
135 |
136 | def _ir_recv_thread(self):
137 | while True:
138 | if (time.ticks_us()-self._prev_time) > self.waittime * 1000 and self.pulse_buffer != []:
139 | if self._lead_cheak():
140 | if len(self.pulse_buffer) >= 66:
141 | decode = self.decode_pulse_nec()
142 | if self.debug:
143 | self._print_debug(decode)
144 | self.pulse_buffer = []
145 | self._prev_time = 0
146 |
147 | if self.callback != None:
148 | self.callback(decode[:1],decode[2:3]) # Address ,Command
149 | else:
150 | print("Warning: Buffer length too short!")
151 | self.pulse_buffer = []
152 | self._prev_time = 0
153 |
154 | else:
155 | print("Warning: Buffer lead code error!")
156 | self.pulse_buffer = []
157 | self._prev_time = 0
158 |
159 | gc.collect()
160 |
161 | def set_callback(self, callback=None):
162 | """function to allow the user to set
163 | or change the callback function. farmat,callback(address ,command) """
164 | self.callback = callback
165 |
166 | def remove_callback(self):
167 | """remove_callback, function to allow the user to remove
168 | the callback function used at any time"""
169 | self.callback = None
170 |
171 | def set_debug(self, debug=True):
172 | """set_debug, function to turn verbose mode
173 | on or off. Used to print out pulse width list
174 | """
175 | self.debug = debug
176 |
177 | class IRTransmit:
178 | """IR NEC signal transmits"""
179 | def __init__(self,pin):
180 | self.ir_transmit = PWM(Pin(pin), duty=0, freq=38000)
181 |
182 | def _mark(self,us):
183 | self.ir_transmit.duty(512)
184 | time.sleep_us(us)
185 |
186 | def _space(self,us):
187 | self.ir_transmit.duty(0)
188 | time.sleep_us(us)
189 |
190 | def _bit(self, bit):
191 | # print(bit)
192 | self._mark(_Const.NEC_BIT_MARK)
193 | if bit:
194 | self._space(_Const.NEC_BIT_MARK*3)
195 | else:
196 | self._space(_Const.NEC_BIT_MARK)
197 |
198 | def _generate_bits(self,addr,cmd):
199 | if type(addr) == bytes :
200 | addr = int.from_bytes(addr,'little')&0xff
201 | if type(cmd) == bytes :
202 | cmd = int.from_bytes(cmd,'little')&0xff
203 | self._payload =[]
204 | for i in range(4):
205 | self._payload.append([])
206 | for i in range(8):
207 | if (addr>>i)&0x01:
208 | self._payload[0].append(1)
209 | self._payload[1].append(0)
210 | else:
211 | self._payload[0].append(0)
212 | self._payload[1].append(1)
213 | for i in range(8):
214 | if (cmd>>i)&0x01:
215 | self._payload[2].append(1)
216 | self._payload[3].append(0)
217 | else:
218 | self._payload[2].append(0)
219 | self._payload[3].append(1)
220 |
221 | def send(self,address,command):
222 | """send NEC data"""
223 | self._generate_bits(address,command)
224 | print(self._payload)
225 | self._mark(_Const.NEC_HDR_MARK)
226 | self._space(_Const.NEC_HDR_SPACE)
227 | for i in range(4):
228 | for j in range(8):
229 | self._bit(self._payload[i][j])
230 | self._mark(560)
231 | self._space(40000)
232 |
233 |
234 |
235 |
--------------------------------------------------------------------------------
/library/ledstrip/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 labplus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/library/ledstrip/MANIFEST:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/ledstrip/MANIFEST
--------------------------------------------------------------------------------
/library/ledstrip/README.md:
--------------------------------------------------------------------------------
1 | ledstrip module 是 micropython neopixel module的增强版,在neopixel基础功能上封装多种的灯带显示效果。
2 | 支持掌控板或micropython的使用。
3 |
4 |
5 | ## 库的安装方法
6 |
7 | 可通过以下任一方法进行安装。
8 | 1. 将项目中的`ledstrip.py`拷到掌控板文件系统上
9 | 2. 在掌控板REPL界面中,使用upip安装,步骤如下:
10 | * 前置条件需要掌控板连接网络
11 | * 导入upip模块,执行`import upip`
12 | * 执行`upip.install('mPython-ledstrip')
13 |
14 | ```python
15 | >>> import upip
16 | >>> upip.install('mPython-ledstrip')
17 | ```
18 | ## 简单示例
19 |
20 | ```python
21 | from ledstrip import *
22 | from machine import Pin
23 |
24 | strip=LedStrip(pin=Pin.P15,n=24,brightness=0.5)
25 |
26 | print("rainbow")
27 | strip.rainbow()
28 | print("rainbow_cycle")
29 | strip.rainbow_cycle()
30 | print("cycle")
31 | strip.cycle((50,50,50))
32 | print("bounce")
33 | strip.bounce((0,0,50))
34 | strip.clear()
35 | print("colorWipe")
36 | strip.colorWipe((0,50,0))
37 | print("theaterChase")
38 | strip.theaterChase((50,0,0))
39 | print("theaterChaseRainbow")
40 | strip.theaterChaseRainbow(wait=5)
41 | print("cylonBounce")
42 | strip.cylonBounce((0,0,50),4,10,50)
43 | print("runningLight")
44 | strip.runningLight((50,50,0),20)
45 |
46 | print("meteorRain")
47 | for i in range(5):
48 | strip.meteorRain((100,100,100),8,60,True,20)
49 | ```
50 |
51 |
52 | ## API 说明
53 |
54 | | 函数 | 功能说明 | 参数 |
55 | | :------ | :------ | :------ |
56 | | hsv2rgb(hsv) |将HSV颜色三元组转换为RGB三元组 | ``hsv`` - 三元组 |
57 | | rgb2hsv(rgb) |将RGB颜色三元组转换为HSV三元组 | ``rgb`` - 三元组 |
58 | | wheel(pos) |彩轮,将0~255值转换为RGB三元组 | ``pos`` - 0~255 |
59 | |LedStrip( pin, n=24, brightness=1.0, timing=1) |LedStrip类初始化 | ``pin`` - 引脚; ``n`` - 灯数 ``brightness`` - 亮度设置,范围0~1.0;``timing`` -速率,1为800Khz,0为400kHz |
60 | | LedStrip.clear() | 熄灭所有灯,不用write()即可生效| /|
61 | | LedStrip.brightness(brightness) | 设置灯带亮度| ``brightness`` - 0~1.0|
62 | | LedStrip.rainbow(wait_us=20) | 彩虹效果| ``wait_us`` - 等待时间,默认20毫秒|
63 | | LedStrip.rainbow_cycle(wait_us=20) | 彩虹环效果:与rainbow略有不同,彩虹在整个过程中均匀分布| ``wait_us`` - 等待时间,默认20毫秒|
64 | | LedStrip.cycle(c, wait=20) |循环效果:有一个像素在所有灯带位置上运行,而其他像素关闭。 | ``c`` - 显示灯RGB颜色,(r,g,b)三元组; ``wait`` - 等待时间,单位毫秒,默认20|
65 | | LedStrip.bounce(c, wait=20) |弹跳效果:弹跳效应和接受(R,G,B)来设置颜色,以及等待时间。等待时间决定了弹跳效果的速度。 | ``c`` - 显示灯RGB颜色,(r,g,b)三元组;``wait`` - 等待时间,单位毫秒,默认20|
66 | | LedStrip.colorWipe(c, wait=20) |逐个填充颜色 | ``c`` - 填充RGB颜色,(r,g,b)三元组;``wait`` - 等待时间,单位毫秒,默认20|
67 | | LedStrip.theaterChase(c, wait=20) |剧院风格的追逐灯效果 | ``c`` - 填充RGB颜色,(r,g,b)三元组;``wait`` - 等待时间,单位毫秒,默认20|
68 | | LedStrip.theaterChaseRainbow(wait=20) |剧院风格的追逐灯效果 | ``wait`` - 等待时间,单位毫秒,默认20|
69 | | LedStrip.cylonBounce(c, eye_size, spee_delay, return_delay) |Cylon效果:模拟Cylon移动“眼睛”的效果:一个红色的“眼睛”从左到右,一次又一次地向后移动 | ``eye_size`` - 运行的LED数量,或:“眼睛”的宽度(外部2,褪色,LED未计数);``spee_delay`` -影响眼睛移动的速度,较高的值意味着移动缓慢; ``return_delay`` - 设置应该等待反弹的时间|
70 | | LedStrip.runningLight(c,wait) |行走灯效果:多组LED相互追逐。亲切 - 就像你在节日期间用来在商店看到的行车灯一样 | ``c`` - 显示灯RGB颜色,(r,g,b)三元组; ``wait`` - 等待时间,单位毫秒0 |
71 | | LedStrip.meteorRain(c,size,trail_decay,random_decay,delay) |流星雨效果 | ``c`` - 显示灯RGB颜色,(r,g,b)三元组;``size`` - 设置流星大小代表流星的LED数量,不计算流星的尾部; ``trail_decay`` - 流星尾部衰减/消失的速度。数字越大,尾部越短和/或消失得越快。理论上,值为64时,每次流星绘制时亮度都会降低25%; ``delay`` - 延时 |
72 |
73 | ## 执照
74 |
75 | 所有代码均在MIT许可下发布。
--------------------------------------------------------------------------------
/library/ledstrip/examples/ledstrip_simple.py:
--------------------------------------------------------------------------------
1 | from ledstrip import *
2 | from machine import Pin
3 |
4 | strip=LedStrip(pin=Pin.P15,n=24,brightness=0.5)
5 |
6 | print("rainbow")
7 | strip.rainbow()
8 | print("rainbow_cycle")
9 | strip.rainbow_cycle()
10 | print("cycle")
11 | strip.cycle((50,50,50))
12 | print("bounce")
13 | strip.bounce((0,0,50))
14 | strip.clear()
15 | print("colorWipe")
16 | strip.colorWipe((0,50,0))
17 | print("theaterChase")
18 | strip.theaterChase((50,0,0))
19 | print("theaterChaseRainbow")
20 | strip.theaterChaseRainbow(wait=5)
21 | print("cylonBounce")
22 | strip.cylonBounce((0,0,50),4,10,50)
23 | print("runningLight")
24 | strip.runningLight((50,50,0),20)
25 |
26 | print("meteorRain")
27 | for i in range(5):
28 | strip.meteorRain((100,100,100),8,60,True,20)
--------------------------------------------------------------------------------
/library/ledstrip/ledstrip.py:
--------------------------------------------------------------------------------
1 |
2 | from neopixel import *
3 | from machine import Pin
4 | from time import sleep_us, sleep_ms
5 | import math
6 | from random import randint
7 |
8 | def hsv2rgb(hsv):
9 | h = float(hsv[0])
10 | s = float(hsv[1])
11 | v = float(hsv[2])
12 | h60 = h / 60.0
13 | h60f = math.floor(h60)
14 | hi = int(h60f) % 6
15 | f = h60 - h60f
16 | p = v * (1 - s)
17 | q = v * (1 - f * s)
18 | t = v * (1 - (1 - f) * s)
19 | r, g, b = 0, 0, 0
20 | if hi == 0:
21 | r, g, b = v, t, p
22 | elif hi == 1:
23 | r, g, b = q, v, p
24 | elif hi == 2:
25 | r, g, b = p, v, t
26 | elif hi == 3:
27 | r, g, b = p, q, v
28 | elif hi == 4:
29 | r, g, b = t, p, v
30 | elif hi == 5:
31 | r, g, b = v, p, q
32 | r, g, b = int(r * 255), int(g * 255), int(b * 255)
33 | return r, g, b
34 |
35 |
36 | def rgb2hsv(rgb):
37 | r, g, b = rgb[0]/255.0, rgb[1]/255.0, rgb[2]/255.0
38 | mx = max(r, g, b)
39 | mn = min(r, g, b)
40 | df = mx-mn
41 | if mx == mn:
42 | h = 0
43 | elif mx == r:
44 | h = (60 * ((g-b)/df) + 360) % 360
45 | elif mx == g:
46 | h = (60 * ((b-r)/df) + 120) % 360
47 | elif mx == b:
48 | h = (60 * ((r-g)/df) + 240) % 360
49 | if mx == 0:
50 | s = 0
51 | else:
52 | s = df/mx
53 | v = mx
54 | return round(h,2), round(s,2), round(v,2)
55 |
56 |
57 | def wheel(pos):
58 | # Input a value 0 to 255 to get a color value.
59 | # The colours are a transition r - g - b - back to r.
60 | if pos < 0 or pos > 255:
61 | r = g = b = 0
62 | elif pos < 85:
63 | r = int(pos * 3)
64 | g = int(255 - pos*3)
65 | b = 0
66 | elif pos < 170:
67 | pos -= 85
68 | r = int(255 - pos*3)
69 | g = 0
70 | b = int(pos*3)
71 | else:
72 | pos -= 170
73 | r = 0
74 | g = int(pos*3)
75 | b = int(255 - pos*3)
76 | return (r, g, b)
77 |
78 |
79 | class LedStrip(NeoPixel):
80 |
81 | def __init__(self, pin, n=24, brightness=0.5, timing=1):
82 | self._brightness = brightness
83 | useable_pin = [Pin.P5, Pin.P6, Pin.P8, Pin.P9, Pin.P11,
84 | Pin.P13, Pin.P14, Pin.P15, Pin.P16, Pin.P19, Pin.P20]
85 | if pin not in useable_pin:
86 | raise TypeError('neopixel not supported in IO%d' % pin)
87 | super().__init__(Pin(pin), n=n, bpp=3, timing=timing)
88 |
89 | def clear(self):
90 | # 熄灭所有RGB
91 | for i in range(self.n):
92 | self[i] = (0, 0, 0)
93 | self.write()
94 |
95 | def write(self):
96 | if self._brightness > 0.99:
97 | neopixel_write(self.pin, self.buf, self.timing)
98 | else:
99 | neopixel_write(self.pin, bytearray([int(i * self._brightness) for i in self.buf]), self.timing)
100 |
101 | def brightness(self, brightness):
102 | self._brightness = min(max(brightness, 0.0), 1.0)
103 |
104 | def rainbow(self, wait_us=20):
105 | # 彩虹效果
106 | for j in range(255):
107 |
108 | for i in range(self.n):
109 | self[i] = wheel((i+j) & 255)
110 | self.write()
111 | sleep_us(wait_us)
112 |
113 | def rainbow_cycle(self, wait_us=20):
114 | # 与rainbow略有不同,这使得彩虹在整个过程中均匀分布
115 | for j in range(255):
116 | for i in range(self.n):
117 | pixel_index = (i * 256 // self.n) + j
118 | self[i] = wheel(pixel_index & 255)
119 | self.write()
120 | sleep_us(wait_us)
121 |
122 | def cycle(self, c, wait=20):
123 | # 循环效果,有一个像素在所有灯带位置上运行,而其他像素关闭。
124 | for i in range(4 * self.n):
125 | for j in range(self.n):
126 | self[j] = (0, 0, 0)
127 | self[i % self.n] = c
128 | self.write()
129 | sleep_ms(wait)
130 |
131 | def bounce(self, c, wait=20):
132 | # 弹跳效果,等待时间决定了弹跳效果的速度
133 | for i in range(4 * self.n):
134 | for j in range(self.n):
135 | self[j] = c
136 | if (i // self.n) % 2 == 0:
137 | self[i % self.n] = (0, 0, 0)
138 | else:
139 | self[self.n - 1 - (i % self.n)] = (0, 0, 0)
140 | self.write()
141 | sleep_ms(wait)
142 |
143 | def colorWipe(self, c, wait=10):
144 | # 逐个填充颜色
145 | # Fill the dots one after the other with a color
146 | for i in range(self.n):
147 | self[i] = c
148 | sleep_ms(wait)
149 | self.write()
150 | sleep_ms(wait)
151 |
152 | def theaterChase(self, c, wait=50):
153 | # 剧院风格的追逐灯
154 | for j in range(10):
155 | for q in range(3):
156 | for i in range(0, self.n, 3):
157 | self[i+q] = c
158 | self.write()
159 | sleep_ms(wait)
160 | for i in range(0, self.n, 3):
161 | self[i+q] = (0, 0, 0)
162 |
163 | def theaterChaseRainbow(self, wait=50):
164 | # 剧院风格的追逐灯带rainbow效果
165 | for j in range(256):
166 | for q in range(3):
167 | for i in range(0, self.n, 3):
168 |
169 | self[i+q] = wheel((i+j) % 255)
170 | self.write()
171 | sleep_ms(wait)
172 | for i in range(0, self.n, 3):
173 | self[i+q] = (0, 0, 0)
174 |
175 | def cylonBounce(self, c, eye_size, spee_delay, return_delay):
176 | """
177 | 我想我们并不是所有人都知道Cylon是什么,但我和那些很酷的机器人一起长大,我肯定想拥有一个。我熟悉骑士骑士(尽管那个时代差不多)?它很亲切 - 类似。这种类型的“扫描仪”通常被称为拉尔森扫描仪,
178 | 以Glen Larson的名字命名,Glen Larson是负责制作原始太空堡垒卡拉狄加和骑士骑士电视节目的人。无论如何,这里有一个模拟Cylon移动“眼睛”的效果:一个红色的“眼睛”从左到右,一次又一次地向后移动。
179 | 亲切 - 一个充满弹性的球哈哈。
180 | :param eye_size-确定运行的LED数量,或:“眼睛”的宽度(外部2,褪色,LED未计数)
181 | :param spee_delay-影响眼睛移动的速度,较高的值意味着移动缓慢。
182 | :param return_delay-设置应该等待反弹的时间
183 | """
184 | for i in range(self.n-eye_size - 2):
185 | self.fill((0, 0, 0))
186 | self[i] = (int(c[0]/10), int(c[1]/10), int(c[2]/10))
187 | for j in range(1, eye_size+1):
188 | self[i+j] = c
189 | self[i+eye_size+1] = (int(c[0]/10), int(c[1]/10), int(c[2]/10))
190 | self.write()
191 | sleep_ms(spee_delay)
192 |
193 | sleep_ms(return_delay)
194 |
195 | for i in range(self.n-eye_size - 2, 0, -1):
196 | self.fill((0, 0, 0))
197 | self[i] = (int(c[0]/10), int(c[1]/10), int(c[2]/10))
198 | for j in range(1, eye_size+1):
199 | self[i+j] = c
200 | self[i+eye_size+1] = (int(c[0]/10), int(c[1]/10), int(c[2]/10))
201 | self.write()
202 | sleep_ms(spee_delay)
203 |
204 | sleep_ms(return_delay)
205 |
206 | def runningLight(self, c, wait):
207 | """
208 | 这种效应使得多组LED相互追逐。亲切 - 就像你在节日期间用来在商店看到的行车灯一样。
209 | :param wait表示循环中放入了多少延迟,数字越大,它就越慢。
210 | """
211 | position = 0
212 | for j in range(self.n * 2):
213 | position += 1
214 | for i in range(self.n):
215 | self[i] = (int(((math.sin(i+position) * 127 + 128)/255)*c[0]),
216 | int(((math.sin(i+position) * 127 + 128)/255)*c[1]),
217 | int(((math.sin(i+position) * 127 + 128)/255)*c[2]))
218 | self.write()
219 | sleep_ms(wait)
220 |
221 | def meteorRain(self,c,size,trail_decay,random_decay,delay):
222 | """
223 | 流星雨效果
224 | :param size - 设置流星大小代表流星的LED数量,不计算流星的尾部
225 | :param trail_decay - 流星尾部衰减/消失的速度。数字越大,尾部越短和/或消失得越快。理论上,值为64时,每次流星绘制时亮度都会降低25%
226 | :param random_decay - 随机衰变-通过使衰变有点随机来模仿碎片中的某些差异。如果此值设置为“true”,则会向轨道添加一些随机性。如果将值设置为“false”,则尾部将非常平滑
227 | :param delay - 延时
228 |
229 | """
230 |
231 | self.fill((0,0,0))
232 | def fadeToBlack(ledNo, fadeValue):
233 |
234 | r = self.buf[ledNo*3+0]
235 | g = self.buf[ledNo*3+1]
236 | b = self.buf[ledNo*3+2]
237 |
238 | r = (0 if (r<=10) else r-int(r*fadeValue/256 ))
239 | g = (0 if (g<=10) else g-int(g*fadeValue/256 ))
240 | b = (0 if (b<=10) else b-int(b*fadeValue/256 ))
241 |
242 | self[ledNo]=(r,g,b)
243 |
244 | for i in range(self.n*2):
245 |
246 | for j in range(self.n):
247 | if (not random_decay) or (randint(0,10) > 5) :
248 | fadeToBlack(j, trail_decay )
249 |
250 | for j in range(size):
251 | if ( i-j =0) :
252 |
253 | self[i-j]=c
254 |
255 | self.write()
256 | sleep_ms(delay)
257 |
--------------------------------------------------------------------------------
/library/ledstrip/optimize_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This script optimizes a Python source distribution tarball as produced by
3 | # "python3 setup.py sdist" command for MicroPython's native package manager,
4 | # upip. Optimization includes:
5 | # * Removing metadata files not used by upip (this includes setup.py)
6 | # * Recompressing gzip archive with 4K dictionary size so it can be
7 | # installed even on low-heap targets.
8 | #
9 | import sys
10 | import os
11 | import zlib
12 | from subprocess import Popen, PIPE
13 | import glob
14 | import tarfile
15 | import re
16 | import io
17 |
18 |
19 | def gzip_4k(inf, fname):
20 | comp = zlib.compressobj(level=9, wbits=16 + 12)
21 | with open(fname + ".out", "wb") as outf:
22 | while 1:
23 | data = inf.read(1024)
24 | if not data:
25 | break
26 | outf.write(comp.compress(data))
27 | outf.write(comp.flush())
28 | os.rename(fname, fname + ".orig")
29 | os.rename(fname + ".out", fname)
30 |
31 |
32 | def recompress(fname):
33 | with Popen(["gzip", "-d", "-c", fname], stdout=PIPE).stdout as inf:
34 | gzip_4k(inf, fname)
35 |
36 | def find_latest(dir):
37 | res = []
38 | for fname in glob.glob(dir + "/*.gz"):
39 | st = os.stat(fname)
40 | res.append((st.st_mtime, fname))
41 | res.sort()
42 | latest = res[-1][1]
43 | return latest
44 |
45 |
46 | def recompress_latest(dir):
47 | latest = find_latest(dir)
48 | print(latest)
49 | recompress(latest)
50 |
51 |
52 | FILTERS = [
53 | # include, exclude, repeat
54 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
55 | (r".+\.py$", r"[^/]+$"),
56 | (None, r".+\.egg-info/.+"),
57 | ]
58 |
59 |
60 | outbuf = io.BytesIO()
61 |
62 | def filter_tar(name):
63 | fin = tarfile.open(name, "r:gz")
64 | fout = tarfile.open(fileobj=outbuf, mode="w")
65 | for info in fin:
66 | # print(info)
67 | if not "/" in info.name:
68 | continue
69 | fname = info.name.split("/", 1)[1]
70 | include = None
71 |
72 | for inc_re, exc_re in FILTERS:
73 | if include is None and inc_re:
74 | if re.match(inc_re, fname):
75 | include = True
76 |
77 | if include is None and exc_re:
78 | if re.match(exc_re, fname):
79 | include = False
80 |
81 | if include is None:
82 | include = True
83 |
84 | if include:
85 | print("Including:", fname)
86 | else:
87 | print("Excluding:", fname)
88 | continue
89 |
90 | farch = fin.extractfile(info)
91 | fout.addfile(info, farch)
92 | fout.close()
93 | fin.close()
94 |
95 |
96 |
97 | from setuptools import Command
98 |
99 | class OptimizeUpip(Command):
100 |
101 | user_options = []
102 |
103 | def run(self):
104 | latest = find_latest("dist")
105 | filter_tar(latest)
106 | outbuf.seek(0)
107 | gzip_4k(outbuf, latest)
108 |
109 | def initialize_options(self):
110 | pass
111 |
112 | def finalize_options(self):
113 | pass
114 |
115 |
116 | # For testing only
117 | if __name__ == "__main__":
118 | # recompress_latest(sys.argv[1])
119 | filter_tar(sys.argv[1])
120 | outbuf.seek(0)
121 | gzip_4k(outbuf, sys.argv[1])
122 |
--------------------------------------------------------------------------------
/library/ledstrip/sdist_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This module overrides distutils (also compatible with setuptools) "sdist"
3 | # command to perform pre- and post-processing as required for MicroPython's
4 | # upip package manager.
5 | #
6 | # Preprocessing steps:
7 | # * Creation of Python resource module (R.py) from each top-level package's
8 | # resources.
9 | # Postprocessing steps:
10 | # * Removing metadata files not used by upip (this includes setup.py)
11 | # * Recompressing gzip archive with 4K dictionary size so it can be
12 | # installed even on low-heap targets.
13 | #
14 | import sys
15 | import os
16 | import zlib
17 | from subprocess import Popen, PIPE
18 | import glob
19 | import tarfile
20 | import re
21 | import io
22 |
23 | from distutils.filelist import FileList
24 | from setuptools.command.sdist import sdist as _sdist
25 |
26 |
27 | def gzip_4k(inf, fname):
28 | comp = zlib.compressobj(level=9, wbits=16 + 12)
29 | with open(fname + ".out", "wb") as outf:
30 | while 1:
31 | data = inf.read(1024)
32 | if not data:
33 | break
34 | outf.write(comp.compress(data))
35 | outf.write(comp.flush())
36 | os.rename(fname, fname + ".orig")
37 | os.rename(fname + ".out", fname)
38 |
39 |
40 | FILTERS = [
41 | # include, exclude, repeat
42 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
43 | (r".+\.py$", r"[^/]+$"),
44 | (None, r".+\.egg-info/.+"),
45 | ]
46 |
47 |
48 | outbuf = io.BytesIO()
49 |
50 | def filter_tar(name):
51 | fin = tarfile.open(name, "r:gz")
52 | fout = tarfile.open(fileobj=outbuf, mode="w")
53 | for info in fin:
54 | # print(info)
55 | if not "/" in info.name:
56 | continue
57 | fname = info.name.split("/", 1)[1]
58 | include = None
59 |
60 | for inc_re, exc_re in FILTERS:
61 | if include is None and inc_re:
62 | if re.match(inc_re, fname):
63 | include = True
64 |
65 | if include is None and exc_re:
66 | if re.match(exc_re, fname):
67 | include = False
68 |
69 | if include is None:
70 | include = True
71 |
72 | if include:
73 | print("including:", fname)
74 | else:
75 | print("excluding:", fname)
76 | continue
77 |
78 | farch = fin.extractfile(info)
79 | fout.addfile(info, farch)
80 | fout.close()
81 | fin.close()
82 |
83 |
84 | def make_resource_module(manifest_files):
85 | resources = []
86 | # Any non-python file included in manifest is resource
87 | for fname in manifest_files:
88 | ext = fname.rsplit(".", 1)[1]
89 | if ext != "py":
90 | resources.append(fname)
91 |
92 | if resources:
93 | print("creating resource module R.py")
94 | resources.sort()
95 | last_pkg = None
96 | r_file = None
97 | for fname in resources:
98 | try:
99 | pkg, res_name = fname.split("/", 1)
100 | except ValueError:
101 | print("not treating %s as a resource" % fname)
102 | continue
103 | if last_pkg != pkg:
104 | last_pkg = pkg
105 | if r_file:
106 | r_file.write("}\n")
107 | r_file.close()
108 | r_file = open(pkg + "/R.py", "w")
109 | r_file.write("R = {\n")
110 |
111 | with open(fname, "rb") as f:
112 | r_file.write("%r: %r,\n" % (res_name, f.read()))
113 |
114 | if r_file:
115 | r_file.write("}\n")
116 | r_file.close()
117 |
118 |
119 | class sdist(_sdist):
120 |
121 | def run(self):
122 | self.filelist = FileList()
123 | self.get_file_list()
124 | make_resource_module(self.filelist.files)
125 |
126 | r = super().run()
127 |
128 | assert len(self.archive_files) == 1
129 | print("filtering files and recompressing with 4K dictionary")
130 | filter_tar(self.archive_files[0])
131 | outbuf.seek(0)
132 | gzip_4k(outbuf, self.archive_files[0])
133 |
134 | return r
135 |
136 |
137 | # For testing only
138 | if __name__ == "__main__":
139 | filter_tar(sys.argv[1])
140 | outbuf.seek(0)
141 | gzip_4k(outbuf, sys.argv[1])
142 |
--------------------------------------------------------------------------------
/library/ledstrip/setup.cfg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/ledstrip/setup.cfg
--------------------------------------------------------------------------------
/library/ledstrip/setup.py:
--------------------------------------------------------------------------------
1 | # import sys
2 | # sys.path.pop(0)
3 | # sys.path.append("..")
4 | from setuptools import setup
5 | import sdist_upip
6 | from os import path
7 |
8 | # read the contents of your README file
9 | from os import path
10 | this_directory = path.abspath(path.dirname(__file__))
11 | with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
12 | long_description = f.read()
13 |
14 | setup(name='mPython-ledstrip',
15 | version='0.0.4',
16 | description='',
17 | long_description=long_description,
18 | long_description_content_type="text/markdown",
19 | url='https://github.com/labplus-cn/mPython_ledstrip',
20 | author='tangliufeng',
21 | author_email='137513285@qq.com',
22 | maintainer='LabPlus Developers',
23 | license='MIT',
24 | cmdclass={'sdist': sdist_upip.sdist},
25 | py_modules=['ledstrip'],
26 | # spackages=['email'],
27 | # install_requires=['']
28 | )
29 |
30 |
--------------------------------------------------------------------------------
/library/microbit/README.md:
--------------------------------------------------------------------------------
1 | 使用该库,Micro:Bit程序可在掌控板上运行。
2 |
3 | ### 已实现Micro:Bit 功能
4 |
5 | - MicrBit Module
6 | - Button
7 | - Pin
8 | - Display
9 | - Image
10 | - UART
11 | - I2C
12 | - Accelerometer
13 | - Compass
14 |
15 |
16 | ## 使用
17 |
18 | 例:
19 |
20 | ```
21 | from microbit import *
22 | display.show(Image.HAPPY)
23 |
24 | ```
25 |
--------------------------------------------------------------------------------
/library/microbit/microbit.py:
--------------------------------------------------------------------------------
1 | # The MIT License (MIT)
2 |
3 | # Copyright (c) 2019, labplus@Tangliufeng
4 |
5 | # Permission is hereby granted, free of charge, to any person obtaining a copy
6 | # of this software and associated documentation files (the "Software"), to deal
7 | # in the Software without restriction, including without limitation the rights
8 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | # copies of the Software, and to permit persons to whom the Software is
10 | # furnished to do so, subject to the following conditions:
11 |
12 | # The above copyright notice and this permission notice shall be included in
13 | # all copies or substantial portions of the Software.
14 |
15 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | # THE SOFTWARE.
22 |
23 | # 掌控板兼容Microbit库,已实现功能有以下:
24 | # - MicrBit Module 基础函数
25 | # - MicroBitDispl
26 | # - 内置Image图片和构建类
27 |
28 | import os,sys,time,_thread,esp32,framebuf,machine,gc
29 | from framebuf import FrameBuffer
30 | from machine import UART
31 | from mpython import oled, MPythonPin, PinMode, ADC, button_a, button_b, accelerometer
32 |
33 | pendolino = [0x0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x8, 0x8, 0x0, 0x8, 0xa, 0x4a, 0x40, 0x0, 0x0, 0xa, 0x5f, 0xea, 0x5f, 0xea, 0xe, 0xd9, 0x2e, 0xd3, 0x6e, 0x19, 0x32, 0x44, 0x89, 0x33, 0xc, 0x92, 0x4c, 0x92, 0x4d, 0x8, 0x8, 0x0, 0x0, 0x0, 0x4, 0x88, 0x8, 0x8, 0x4, 0x8, 0x4, 0x84, 0x84, 0x88, 0x0, 0xa, 0x44, 0x8a, 0x40, 0x0, 0x4, 0x8e, 0xc4, 0x80, 0x0, 0x0, 0x0, 0x4, 0x88, 0x0, 0x0, 0xe, 0xc0, 0x0, 0x0, 0x0, 0x0, 0x8, 0x0, 0x1, 0x22, 0x44, 0x88, 0x10, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x4, 0x8c, 0x84, 0x84, 0x8e, 0x1c, 0x82, 0x4c, 0x90, 0x1e, 0x1e, 0xc2, 0x44, 0x92, 0x4c, 0x6, 0xca, 0x52, 0x5f, 0xe2, 0x1f, 0xf0, 0x1e, 0xc1, 0x3e, 0x2, 0x44, 0x8e, 0xd1, 0x2e, 0x1f, 0xe2, 0x44, 0x88, 0x10, 0xe, 0xd1, 0x2e, 0xd1, 0x2e, 0xe, 0xd1, 0x2e, 0xc4, 0x88, 0x0, 0x8, 0x0, 0x8, 0x0, 0x0, 0x4, 0x80, 0x4, 0x88, 0x2, 0x44, 0x88, 0x4, 0x82, 0x0, 0xe, 0xc0, 0xe, 0xc0, 0x8, 0x4, 0x82, 0x44, 0x88, 0xe, 0xd1, 0x26, 0xc0, 0x4, 0xe, 0xd1, 0x35, 0xb3, 0x6c, 0xc, 0x92, 0x5e, 0xd2, 0x52, 0x1c, 0x92, 0x5c, 0x92, 0x5c, 0xe, 0xd0, 0x10, 0x10, 0xe, 0x1c, 0x92, 0x52, 0x52, 0x5c, 0x1e, 0xd0, 0x1c, 0x90, 0x1e, 0x1e, 0xd0, 0x1c, 0x90, 0x10, 0xe, 0xd0, 0x13, 0x71, 0x2e, 0x12, 0x52, 0x5e, 0xd2, 0x52, 0x1c, 0x88, 0x8, 0x8, 0x1c, 0x1f, 0xe2, 0x42, 0x52, 0x4c, 0x12, 0x54, 0x98, 0x14, 0x92, 0x10, 0x10, 0x10, 0x10, 0x1e, 0x11, 0x3b, 0x75, 0xb1, 0x31, 0x11, 0x39, 0x35, 0xb3, 0x71, 0xc, 0x92, 0x52, 0x52, 0x4c, 0x1c, 0x92, 0x5c, 0x90, 0x10, 0xc, 0x92, 0x52, 0x4c, 0x86, 0x1c, 0x92, 0x5c, 0x92, 0x51, 0xe, 0xd0, 0xc, 0x82, 0x5c, 0x1f, 0xe4, 0x84, 0x84, 0x84, 0x12, 0x52, 0x52, 0x52, 0x4c, 0x11, 0x31, 0x31, 0x2a, 0x44, 0x11, 0x31, 0x35, 0xbb, 0x71, 0x12, 0x52, 0x4c, 0x92, 0x52, 0x11, 0x2a, 0x44, 0x84, 0x84, 0x1e, 0xc4, 0x88, 0x10, 0x1e, 0xe, 0xc8, 0x8, 0x8, 0xe, 0x10, 0x8, 0x4, 0x82, 0x41, 0xe, 0xc2, 0x42, 0x42, 0x4e, 0x4, 0x8a, 0x40, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1f, 0x8, 0x4, 0x80, 0x0, 0x0, 0x0, 0xe, 0xd2, 0x52, 0x4f, 0x10, 0x10, 0x1c, 0x92, 0x5c, 0x0, 0xe, 0xd0, 0x10, 0xe, 0x2, 0x42, 0x4e, 0xd2, 0x4e, 0xc, 0x92, 0x5c, 0x90, 0xe, 0x6, 0xc8, 0x1c, 0x88, 0x8, 0xe, 0xd2, 0x4e, 0xc2, 0x4c, 0x10, 0x10, 0x1c, 0x92, 0x52, 0x8, 0x0, 0x8, 0x8, 0x8, 0x2, 0x40, 0x2, 0x42, 0x4c, 0x10, 0x14, 0x98, 0x14, 0x92, 0x8, 0x8, 0x8, 0x8, 0x6, 0x0, 0x1b, 0x75, 0xb1, 0x31, 0x0, 0x1c, 0x92, 0x52, 0x52, 0x0, 0xc, 0x92, 0x52, 0x4c, 0x0, 0x1c, 0x92, 0x5c, 0x90, 0x0, 0xe, 0xd2, 0x4e, 0xc2, 0x0, 0xe, 0xd0, 0x10, 0x10, 0x0, 0x6, 0xc8, 0x4, 0x98, 0x8, 0x8, 0xe, 0xc8, 0x7, 0x0, 0x12, 0x52, 0x52, 0x4f, 0x0, 0x11, 0x31, 0x2a, 0x44, 0x0, 0x11, 0x31, 0x35, 0xbb, 0x0, 0x12, 0x4c, 0x8c, 0x92, 0x0, 0x11, 0x2a, 0x44, 0x98, 0x0, 0x1e, 0xc4, 0x88, 0x1e, 0x6, 0xc4, 0x8c, 0x84, 0x86, 0x8, 0x8, 0x8, 0x8, 0x8, 0x18, 0x8, 0xc, 0x88, 0x18, 0x0, 0x0, 0xc, 0x83, 0x60]
34 | pendolino = bytearray(pendolino)
35 |
36 | # microbit引脚映射
37 | def pin_esp2bit(pin):
38 | pins_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,
39 | 13, 15, 4)
40 | if pin == None:
41 | return None
42 | else:
43 | return pins_remap_esp32[pin]
44 |
45 | # 芯片温度
46 | def temperature():
47 | return int((esp32.raw_temperature()-32)/1.8)
48 |
49 | # 复位
50 | def reset():
51 | machine.reset()
52 |
53 | # 毫秒延时
54 | def sleep(n):
55 | time.sleep_ms(n)
56 |
57 | # 运行时间ms
58 | def running_time():
59 | return time.ticks_ms()
60 |
61 |
62 | class MicroBitUART(UART):
63 |
64 | def __init__(self):
65 | super().__init__(1)
66 | self.redirect = False
67 |
68 | def init(self, *arg, **kws):
69 | try:
70 | tx = kws["tx"]
71 | rx = kws["rx"]
72 | except KeyError:
73 | pass
74 | else:
75 | kws['tx'] = pin_esp2bit(tx.id)
76 | kws['rx'] = pin_esp2bit(rx.id)
77 | self.redirect = True
78 | super().init(*arg, **kws)
79 |
80 | def any(self):
81 | if not self.redirect: super().init(115200, tx=1, rx=3)
82 | return super().any()
83 |
84 | def read(self,*arg):
85 | if not self.redirect: super().init(115200, tx=1, rx=3)
86 | return super().read(*arg)
87 |
88 | def readall(self):
89 | if not self.redirect: super().init(115200, tx=1, rx=3)
90 | return super().read()
91 |
92 | def readinto(self,*arg):
93 | if not self.redirect: super().init(115200, tx=1, rx=3)
94 | return super().readinto(*arg)
95 |
96 | def readline(self):
97 | if not self.redirect: super().init(115200, tx=1, rx=3)
98 | return super().readline()
99 |
100 | def write(self,*arg):
101 | if not self.redirect: super().init(115200, tx=1, rx=3)
102 | return super().write(*arg)
103 |
104 |
105 | class Matrix(FrameBuffer):
106 |
107 | def __init__(self):
108 | self.buffer = bytearray(5)
109 | super().__init__(self.buffer, 5, 5, framebuf.MONO_VLSB)
110 | self.grid = 12
111 | self._pixel_o = (37, 5)
112 |
113 | def draw_pixel(self,x,y,c):
114 | pixel = (self._pixel_o[0]+x*self.grid, self._pixel_o[1]+y*self.grid)
115 | oled.fill_rect(pixel[0],pixel[1],int(self.grid/2),int(self.grid/2),c)
116 |
117 | def draw_matrix(self,buf):
118 | temp=bytearray(5)
119 | for i in range(5):
120 | temp[i]=(buf[i]<<3)&0xff
121 | for j in range(5):
122 | if temp[i] << j & 0x80:
123 | self.draw_pixel(i, 4-j, 1)
124 | else:
125 | self.draw_pixel(i,4-j,0)
126 |
127 | def get_char(self,char):
128 | buf = bytearray(5)
129 | buf_v = bytearray(5)
130 | index = 5*(ord(char)-32)
131 | temp = pendolino[index:index+5]
132 | for i in range(5):
133 | buf[i] = (temp[i] << 3) & 0xff
134 | for i in range(5):
135 | for j in range(5):
136 | buf_v[4-i] |= ((buf[j] >> (3+i) & 0x01) << j) & 0xff
137 | return buf_v
138 |
139 | def text(self,text):
140 | self.buffer_text= []
141 | text=str(text)
142 | self.text_length=len(text)
143 | for i in range(self.text_length):
144 | temp=self.get_char(text[i])
145 | temp_list=list(temp)
146 | self.buffer_text.extend(temp_list)
147 | self.buffer_text.append(0)
148 | self.buffer[:]=bytearray(self.buffer_text[0:5])[:]
149 |
150 | def left_shift(self, step):
151 | for i in range(step):
152 | self.buffer_text.append(self.buffer_text[0])
153 | self.buffer_text.pop(0)
154 | self.buffer[:]=bytearray(self.buffer_text[0:5])[:]
155 | self.show()
156 |
157 | def show(self):
158 | self.draw_matrix(self.buffer)
159 | oled.show()
160 |
161 | class MicroBitImage():
162 |
163 | def __init__(self,*arg):
164 | self.buffer = bytearray()
165 | if len(arg)==1:
166 | if type(arg[0]) == str:
167 | self.buffer = self.str2bytes(arg[0])
168 | self._str = arg[0]
169 | else:
170 | raise TypeError("The argument must be a string" )
171 | else:
172 | self._weight =arg[0]
173 | self._height =arg[1]
174 | self.buffer = bytearray(arg[2])
175 | self._str = self.bytes2str(*arg)
176 |
177 | def __repr__(self):
178 | return 'Image({!r})'.format(self._str)
179 |
180 | def str2bytes(self,string):
181 | if string.find(":") ==-1:
182 | list_=string.split()
183 | else:
184 | list_ = string.split(":")
185 | self._height = len(list_)
186 | self._weight = len(list_[0])
187 | buf=bytearray()
188 | for raw in range(self._height):
189 | for col in range(self._weight):
190 | if int(list_[raw][col]):
191 | buf.append(1)
192 | else:
193 | buf.append(0)
194 | return buf
195 |
196 | def bytes2str(self,width,height,buf):
197 | list_=[""]*height
198 | for h in range(height):
199 | for w in range(width):
200 | if buf[h*height+w]:
201 | list_[h]+="9"
202 | else:
203 | list_[h]+="0"
204 | return ":".join(list_)
205 |
206 | def width(self):
207 | return self._weight
208 |
209 | def height(self):
210 | return self._height
211 |
212 | class Image(MicroBitImage):
213 |
214 | HEART = MicroBitImage(5, 5, [
215 | 0, 1, 0, 1, 0,
216 | 1, 1, 1, 1, 1,
217 | 1, 1, 1, 1, 1,
218 | 0, 1, 1, 1, 0,
219 | 0, 0, 1, 0, 0
220 | ])
221 | HEART_SMALL = MicroBitImage(5, 5, [
222 | 0, 0, 0, 0, 0,
223 | 0, 1, 0, 1, 0,
224 | 0, 1, 1, 1, 0,
225 | 0, 0, 1, 0, 0,
226 | 0, 0, 0, 0, 0
227 | ])
228 | HAPPY = MicroBitImage(5, 5, [
229 | 0, 0, 0, 0, 0,
230 | 0, 1, 0, 1, 0,
231 | 0, 0, 0, 0, 0,
232 | 1, 0, 0, 0, 1,
233 | 0, 1, 1, 1, 0
234 | ])
235 |
236 | SMILE = MicroBitImage(5, 5, [
237 | 0, 0, 0, 0, 0,
238 | 0, 1, 0, 1, 0,
239 | 0, 0, 0, 0, 0,
240 | 1, 0, 0, 0, 1,
241 | 0, 1, 1, 1, 0
242 | ])
243 | SAD = MicroBitImage(5, 5, [
244 | 0, 0, 0, 0, 0,
245 | 0, 1, 0, 1, 0,
246 | 0, 0, 0, 0, 0,
247 | 0, 1, 1, 1, 0,
248 | 1, 0, 0, 0, 1
249 | ])
250 |
251 | CONFUSED = MicroBitImage(5, 5, [
252 | 0, 0, 0, 0, 0,
253 | 0, 1, 0, 1, 0,
254 | 0, 0, 0, 0, 0,
255 | 0, 1, 0, 1, 0,
256 | 1, 0, 1, 0, 1
257 | ])
258 |
259 | ANGRY = MicroBitImage(5, 5, [
260 | 1, 0, 0, 0, 1,
261 | 0, 1, 0, 1, 0,
262 | 0, 0, 0, 0, 0,
263 | 1, 1, 1, 1, 1,
264 | 1, 0, 1, 0, 1
265 | ])
266 |
267 | ASLEEP = MicroBitImage(5, 5, [
268 | 0, 0, 0, 0, 0,
269 | 1, 1, 0, 1, 1,
270 | 0, 0, 0, 0, 0,
271 | 0, 1, 1, 1, 0,
272 | 0, 0, 0, 0, 0
273 | ])
274 |
275 | SURPRISED = MicroBitImage(5, 5, [
276 | 0, 1, 0, 1, 0,
277 | 0, 0, 0, 0, 0,
278 | 0, 0, 1, 0, 0,
279 | 0, 1, 0, 1, 0,
280 | 0, 0, 1, 0, 0
281 | ])
282 |
283 | SILLY = MicroBitImage(5, 5, [
284 | 1, 0, 0, 0, 1,
285 | 0, 0, 0, 0, 0,
286 | 1, 1, 1, 1, 1,
287 | 0, 0, 1, 0, 1,
288 | 0, 0, 1, 1, 1
289 | ])
290 | FABULOUS = MicroBitImage(5, 5, [
291 | 1, 1, 1, 1, 1,
292 | 1, 1, 0, 1, 1,
293 | 0, 0, 0, 0, 0,
294 | 0, 1, 0, 1, 0,
295 | 0, 1, 1, 1, 0
296 | ])
297 |
298 | MEH = MicroBitImage(5, 5, [
299 | 0, 1, 0, 1, 0,
300 | 0, 0, 0, 0, 0,
301 | 0, 0, 0, 1, 0,
302 | 0, 0, 1, 0, 0,
303 | 0, 1, 0, 0, 0
304 | ])
305 |
306 | YES = MicroBitImage(5, 5, [
307 | 0, 0, 0, 0, 0,
308 | 0, 0, 0, 0, 1,
309 | 0, 0, 0, 1, 0,
310 | 1, 0, 1, 0, 0,
311 | 0, 1, 0, 0, 0
312 | ])
313 |
314 | NO = MicroBitImage(5, 5, [
315 | 1, 0, 0, 0, 1,
316 | 0, 1, 0, 1, 0,
317 | 0, 0, 1, 0, 0,
318 | 0, 1, 0, 1, 0,
319 | 1, 0, 0, 0, 1
320 | ])
321 |
322 | CLOCK12 = MicroBitImage(5, 5, [
323 | 0, 0, 1, 0, 0,
324 | 0, 0, 1, 0, 0,
325 | 0, 0, 1, 0, 0,
326 | 0, 0, 0, 0, 0,
327 | 0, 0, 0, 0, 0
328 | ])
329 |
330 | CLOCK1 = MicroBitImage(5, 5, [
331 | 0, 0, 0, 1, 0,
332 | 0, 0, 0, 1, 0,
333 | 0, 0, 1, 0, 0,
334 | 0, 0, 0, 0, 0,
335 | 0, 0, 0, 0, 0
336 | ])
337 |
338 | CLOCK2 = MicroBitImage(5, 5, [
339 | 0, 0, 0, 0, 0,
340 | 0, 0, 0, 1, 1,
341 | 0, 0, 1, 0, 0,
342 | 0, 0, 0, 0, 0,
343 | 0, 0, 0, 0, 0
344 | ])
345 |
346 | CLOCK3 = MicroBitImage(5, 5, [
347 | 0, 0, 0, 0, 0,
348 | 0, 0, 0, 0, 0,
349 | 0, 0, 1, 1, 1,
350 | 0, 0, 0, 0, 0,
351 | 0, 0, 0, 0, 0
352 | ])
353 |
354 | CLOCK4 = MicroBitImage(5, 5, [
355 | 0, 0, 0, 0, 0,
356 | 0, 0, 0, 0, 0,
357 | 0, 0, 1, 0, 0,
358 | 0, 0, 0, 1, 1,
359 | 0, 0, 0, 0, 0
360 | ])
361 |
362 | CLOCK5 = MicroBitImage(5, 5, [
363 | 0, 0, 0, 0, 0,
364 | 0, 0, 0, 0, 0,
365 | 0, 0, 1, 0, 0,
366 | 0, 0, 0, 1, 0,
367 | 0, 0, 0, 1, 0
368 | ])
369 |
370 | CLOCK6 = MicroBitImage(5, 5, [
371 | 0, 0, 0, 0, 0,
372 | 0, 0, 0, 0, 0,
373 | 0, 0, 1, 0, 0,
374 | 0, 0, 1, 0, 0,
375 | 0, 0, 1, 0, 0
376 | ])
377 |
378 | CLOCK7 = MicroBitImage(5, 5, [
379 | 0, 0, 0, 0, 0,
380 | 0, 0, 0, 0, 0,
381 | 0, 0, 1, 0, 0,
382 | 0, 1, 0, 0, 0,
383 | 0, 1, 0, 0, 0
384 | ])
385 |
386 | CLOCK8 = MicroBitImage(5, 5, [
387 | 0, 0, 0, 0, 0,
388 | 0, 0, 0, 0, 0,
389 | 0, 0, 1, 0, 0,
390 | 1, 1, 0, 0, 0,
391 | 0, 0, 0, 0, 0
392 | ])
393 |
394 | CLOCK9 = MicroBitImage(5, 5, [
395 | 0, 0, 0, 0, 0,
396 | 0, 0, 0, 0, 0,
397 | 1, 1, 1, 0, 0,
398 | 0, 0, 0, 0, 0,
399 | 0, 0, 0, 0, 0
400 | ])
401 |
402 | CLOCK10 = MicroBitImage(5, 5, [
403 | 0, 0, 0, 0, 0,
404 | 1, 1, 0, 0, 0,
405 | 0, 0, 1, 0, 0,
406 | 0, 0, 0, 0, 0,
407 | 0, 0, 0, 0, 0
408 | ])
409 |
410 | CLOCK11 = MicroBitImage(5, 5, [
411 | 0, 1, 0, 0, 0,
412 | 0, 1, 0, 0, 0,
413 | 0, 0, 1, 0, 0,
414 | 0, 0, 0, 0, 0,
415 | 0, 0, 0, 0, 0
416 | ])
417 |
418 | ARROW_N = MicroBitImage(5, 5, [
419 | 0, 0, 1, 0, 0,
420 | 0, 1, 1, 1, 0,
421 | 1, 0, 1, 0, 1,
422 | 0, 0, 1, 0, 0,
423 | 0, 0, 1, 0, 0
424 | ])
425 |
426 | ARROW_NE = MicroBitImage(5, 5, [
427 | 0, 0, 1, 1, 1,
428 | 0, 0, 0, 1, 1,
429 | 0, 0, 1, 0, 1,
430 | 0, 1, 0, 0, 0,
431 | 1, 0, 0, 0, 0
432 | ])
433 |
434 | ARROW_E = MicroBitImage(5, 5, [
435 | 0, 0, 1, 0, 0,
436 | 0, 0, 0, 1, 0,
437 | 1, 1, 1, 1, 1,
438 | 0, 0, 0, 1, 0,
439 | 0, 0, 1, 0, 0
440 | ])
441 |
442 | ARROW_SE = MicroBitImage(5, 5, [
443 | 1, 0, 0, 0, 0,
444 | 0, 1, 0, 0, 0,
445 | 0, 0, 1, 0, 1,
446 | 0, 0, 0, 1, 1,
447 | 0, 0, 1, 1, 1
448 | ])
449 |
450 | ARROW_S = MicroBitImage(5, 5, [
451 | 0, 0, 1, 0, 0,
452 | 0, 0, 1, 0, 0,
453 | 1, 0, 1, 0, 1,
454 | 0, 1, 1, 1, 0,
455 | 0, 0, 1, 0, 0
456 | ])
457 |
458 | ARROW_SW = MicroBitImage(5, 5, [
459 | 0, 0, 0, 0, 1,
460 | 0, 0, 0, 1, 0,
461 | 1, 0, 1, 0, 0,
462 | 1, 1, 0, 0, 0,
463 | 1, 1, 1, 0, 0
464 | ])
465 | ARROW_W = MicroBitImage(5, 5, [
466 | 0, 0, 1, 0, 0,
467 | 0, 1, 0, 0, 0,
468 | 1, 1, 1, 1, 1,
469 | 0, 1, 0, 0, 0,
470 | 0, 0, 1, 0, 0
471 | ])
472 | ARROW_NW = MicroBitImage(5, 5, [
473 | 1, 1, 1, 0, 0,
474 | 1, 1, 0, 0, 0,
475 | 1, 0, 1, 0, 0,
476 | 0, 0, 0, 1, 0,
477 | 0, 0, 0, 0, 1
478 | ])
479 | TRIANGLE = MicroBitImage(5, 5, [
480 | 0, 0, 0, 0, 0,
481 | 0, 0, 1, 0, 0,
482 | 0, 1, 0, 1, 0,
483 | 1, 1, 1, 1, 1,
484 | 0, 0, 0, 0, 0
485 | ])
486 | TRIANGLE_LEFT = MicroBitImage(5, 5, [
487 | 1, 0, 0, 0, 0,
488 | 1, 1, 0, 0, 0,
489 | 1, 0, 1, 0, 0,
490 | 1, 0, 0, 1, 0,
491 | 1, 1, 1, 1, 1
492 | ])
493 | CHESSBOARD = MicroBitImage(5, 5, [
494 | 0, 1, 0, 1, 0,
495 | 1, 0, 1, 0, 1,
496 | 0, 1, 0, 1, 0,
497 | 1, 0, 1, 0, 1,
498 | 0, 1, 0, 1, 0
499 | ])
500 | DIAMOND_SMALL = MicroBitImage(5, 5, [
501 | 0, 0, 0, 0, 0,
502 | 0, 0, 1, 0, 0,
503 | 0, 1, 0, 1, 0,
504 | 0, 0, 1, 0, 0,
505 | 0, 0, 0, 0, 0
506 | ])
507 | SQUARE = MicroBitImage(5, 5, [
508 | 1, 1, 1, 1, 1,
509 | 1, 0, 0, 0, 1,
510 | 1, 0, 0, 0, 1,
511 | 1, 0, 0, 0, 1,
512 | 1, 1, 1, 1, 1
513 | ])
514 | SQUARE_SMALL = MicroBitImage(5, 5, [
515 | 0, 0, 0, 0, 0,
516 | 0, 1, 1, 1, 0,
517 | 0, 1, 0, 1, 0,
518 | 0, 1, 1, 1, 0,
519 | 0, 0, 0, 0, 0
520 | ])
521 | RABBIT = MicroBitImage(5, 5, [
522 | 1, 0, 1, 0, 0,
523 | 1, 0, 1, 0, 0,
524 | 1, 1, 1, 1, 0,
525 | 1, 1, 0, 1, 0,
526 | 1, 1, 1, 1, 0
527 | ])
528 | COW = MicroBitImage(5, 5, [
529 | 1, 0, 0, 0, 1,
530 | 1, 0, 0, 0, 1,
531 | 1, 1, 1, 1, 1,
532 | 0, 1, 1, 1, 0,
533 | 0, 0, 1, 0, 0
534 | ])
535 | CROTCHET = MicroBitImage(5, 5, [
536 | 0, 0, 1, 0, 0,
537 | 0, 0, 1, 0, 0,
538 | 0, 0, 1, 0, 0,
539 | 1, 1, 1, 0, 0,
540 | 1, 1, 1, 0, 0
541 | ])
542 |
543 | QUAVER = MicroBitImage(5, 5, [
544 | 0, 0, 1, 0, 0,
545 | 0, 0, 1, 1, 0,
546 | 0, 0, 1, 0, 1,
547 | 1, 1, 1, 0, 0,
548 | 1, 1, 1, 0, 0
549 | ])
550 |
551 | QUAVERS = MicroBitImage(5, 5, [
552 | 0, 1, 1, 1, 1,
553 | 0, 1, 0, 0, 1,
554 | 0, 1, 0, 0, 1,
555 | 1, 1, 0, 1, 1,
556 | 1, 1, 0, 1, 1
557 | ])
558 | PITCHFORK = MicroBitImage(5, 5, [
559 | 1, 0, 1, 0, 1,
560 | 1, 0, 1, 0, 1,
561 | 1, 1, 1, 1, 1,
562 | 0, 0, 1, 0, 0,
563 | 0, 0, 1, 0, 0
564 | ])
565 | XMAS = MicroBitImage(5, 5, [
566 | 0, 0, 1, 0, 0,
567 | 0, 1, 1, 1, 0,
568 | 0, 0, 1, 0, 0,
569 | 0, 1, 1, 1, 0,
570 | 1, 1, 1, 1, 1
571 | ])
572 | PACMAN = MicroBitImage(5, 5, [
573 | 0, 1, 1, 1, 1,
574 | 1, 1, 0, 1, 0,
575 | 1, 1, 1, 0, 0,
576 | 1, 1, 1, 1, 0,
577 | 0, 1, 1, 1, 1
578 | ])
579 | TARGET = MicroBitImage(5, 5, [
580 | 0, 0, 1, 0, 0,
581 | 0, 1, 1, 1, 0,
582 | 1, 1, 0, 1, 1,
583 | 0, 1, 1, 1, 0,
584 | 0, 0, 1, 0, 0
585 | ])
586 | TSHIRT = MicroBitImage(5, 5, [
587 | 1, 1, 0, 1, 1,
588 | 1, 1, 1, 1, 1,
589 | 0, 1, 1, 1, 0,
590 | 0, 1, 1, 1, 0,
591 | 0, 1, 1, 1, 0
592 | ])
593 | ROLLERSKATE = MicroBitImage(5, 5, [
594 | 0, 0, 0, 1, 1,
595 | 0, 0, 0, 1, 1,
596 | 1, 1, 1, 1, 1,
597 | 1, 1, 1, 1, 1,
598 | 0, 1, 0, 1, 0
599 | ])
600 | DUCK = MicroBitImage(5, 5, [
601 | 0, 1, 1, 0, 0,
602 | 1, 1, 1, 0, 0,
603 | 0, 1, 1, 1, 1,
604 | 0, 1, 1, 1, 0,
605 | 0, 0, 0, 0, 0
606 | ])
607 | HOUSE = MicroBitImage(5, 5, [
608 | 0, 0, 1, 0, 0,
609 | 0, 1, 1, 1, 0,
610 | 1, 1, 1, 1, 1,
611 | 0, 1, 1, 1, 0,
612 | 0, 1, 0, 1, 0
613 | ])
614 | TORTOISE = MicroBitImage(5, 5, [
615 | 0, 0, 0, 0, 0,
616 | 0, 1, 1, 1, 0,
617 | 1, 1, 1, 1, 1,
618 | 0, 1, 0, 1, 0,
619 | 0, 0, 0, 0, 0
620 | ])
621 | BUTTERFLY = MicroBitImage(5, 5, [
622 | 1, 1, 0, 1, 1,
623 | 1, 1, 1, 1, 1,
624 | 0, 0, 1, 0, 0,
625 | 1, 1, 1, 1, 1,
626 | 1, 1, 0, 1, 1
627 | ])
628 | STICKFIGURE = MicroBitImage(5, 5, [
629 | 0, 0, 1, 0, 0,
630 | 1, 1, 1, 1, 1,
631 | 0, 0, 1, 0, 0,
632 | 0, 1, 0, 1, 0,
633 | 1, 0, 0, 0, 1
634 | ])
635 | GHOST = MicroBitImage(5, 5, [
636 | 1, 1, 1, 1, 1,
637 | 1, 0, 1, 0, 1,
638 | 1, 1, 1, 1, 1,
639 | 1, 1, 1, 1, 1,
640 | 1, 0, 1, 0, 1
641 | ])
642 | SWORD = MicroBitImage(5, 5, [
643 | 0, 0, 1, 0, 0,
644 | 0, 0, 1, 0, 0,
645 | 0, 0, 1, 0, 0,
646 | 0, 1, 1, 1, 0,
647 | 0, 0, 1, 0, 0
648 | ])
649 | GIRAFFE = MicroBitImage(5, 5, [
650 | 1, 1, 0, 0, 0,
651 | 0, 1, 0, 0, 0,
652 | 0, 1, 0, 0, 0,
653 | 0, 1, 1, 1, 0,
654 | 0, 1, 0, 1, 0
655 | ])
656 | SKULL = MicroBitImage(5, 5, [
657 | 0, 1, 1, 1, 0,
658 | 1, 0, 1, 0, 1,
659 | 1, 1, 1, 1, 1,
660 | 0, 1, 1, 1, 0,
661 | 0, 1, 1, 1, 0
662 | ])
663 | UMBRELLA = MicroBitImage(5, 5, [
664 | 0, 1, 1, 1, 0,
665 | 1, 1, 1, 1, 1,
666 | 0, 0, 1, 0, 0,
667 | 1, 0, 1, 0, 0,
668 | 0, 1, 1, 0, 0
669 | ])
670 | SNAKE = MicroBitImage(5, 5, [
671 | 1, 1, 0, 0, 0,
672 | 1, 1, 0, 1, 1,
673 | 0, 1, 0, 1, 0,
674 | 0, 1, 1, 1, 0,
675 | 0, 0, 0, 0, 0
676 | ])
677 |
678 | class MicroBitDisplay():
679 |
680 | def __init__(self):
681 | self.matrix = Matrix()
682 | self.ison = True
683 | _thread.start_new_thread(self._loop, ())
684 | self.lock=_thread.allocate_lock()
685 | self.clear()
686 |
687 | def get_pixel(self, x, y):
688 | temp = (self.matrix.buffer[x] << 3) & 0xff
689 | if temp << 4-y & 0x80:
690 | return True
691 | else:
692 | return False
693 |
694 | def set_pixel(self, x, y, value):
695 | self.matrix.pixel(x,y,value)
696 | self.matrix.show()
697 |
698 | def clear(self):
699 | self.matrix.fill(0)
700 | self.matrix.show()
701 |
702 | def hline(self, *arg ,**kws):
703 | self.matrix.hline(*arg ,**kws)
704 | self.matrix.show()
705 |
706 | def vline(self, *arg ,**kws):
707 | self.matrix.vline(*arg ,**kws)
708 | self.matrix.show()
709 |
710 | def show(self, value,delay = 150,*,wait = True,loop = False,clear = False):
711 | if type(value) == MicroBitImage:
712 | img=value
713 | for h in range(5):
714 | for w in range(5):
715 | if img.buffer[h*5+w]:
716 | self.matrix.pixel(w,h,1)
717 | else:
718 | self.matrix.pixel(w,h,0)
719 | self.matrix.show()
720 | else:
721 | self.scroll(value,delay,wait=wait,loop=loop)
722 | if clear:
723 | self.clear()
724 |
725 | def scroll(self, value, delay=150, *, wait=True, loop=False, monospace=False):
726 | self._wait =wait
727 | self._value = value
728 | self._delay = delay
729 | while loop:
730 | self._text(value,delay)
731 | if self._wait and (not loop):
732 | self._text(value,delay)
733 |
734 |
735 | def _text(self,value,delay):
736 | self.matrix.text(value)
737 | self.matrix.show()
738 | time.sleep_ms(delay)
739 | if self.matrix.text_length >1:
740 | for i in range(len(self.matrix.buffer_text)-5):
741 | self.matrix.left_shift(1)
742 | time.sleep_ms(delay)
743 |
744 |
745 | def _loop(self):
746 | self._wait =True
747 | while True:
748 | if not self._wait:
749 | self._text(self._value,self._delay)
750 | self._wait= True
751 |
752 | def on(self):
753 | oled.poweron()
754 | self.ison = True
755 |
756 | def off(self):
757 | oled.poweroff()
758 | self.ison = False
759 |
760 | def is_on(self):
761 | return self.ison
762 |
763 | class MicroBitPin:
764 | IN = 1
765 | OUT = 2
766 | PWM = 3
767 | ANALOG = 4
768 |
769 | def __init__(self, id):
770 | self.id = id
771 | self.current_mode = None
772 | self.mpython_pin = None
773 |
774 | def __change_pin_mode(self, pinmode):
775 | if self.current_mode is not pinmode:
776 | self.mpython_pin = MPythonPin(self.id, mode=pinmode)
777 | if pinmode == MicroBitPin.ANALOG:
778 | self.mpython_pin.adc.width(ADC.WIDTH_10BIT)
779 | self.current_mode = pinmode
780 |
781 | def read_digital(self):
782 | self.__change_pin_mode(MicroBitPin.IN)
783 | return self.mpython_pin.read_digital()
784 |
785 | def write_digital(self, value):
786 | self.__change_pin_mode(MicroBitPin.OUT)
787 | self.mpython_pin.write_digital(value)
788 |
789 | def read_analog(self):
790 | self.__change_pin_mode(MicroBitPin.ANALOG)
791 | return self.mpython_pin.read_analog()
792 |
793 | def write_analog(self, value):
794 | self.__change_pin_mode(MicroBitPin.PWM)
795 | self.mpython_pin.write_analog(value)
796 |
797 | def set_analog_period(period):
798 | #TODO
799 | pass
800 |
801 | def set_analog_period_microseconds(period):
802 | #TODO
803 | pass
804 |
805 | uart = MicroBitUART()
806 | display=MicroBitDisplay()
807 | # Pin
808 | pin0 = MicroBitPin(0)
809 | pin1 = MicroBitPin(1)
810 | pin2 = MicroBitPin(2)
811 | pin3 = MicroBitPin(3)
812 | pin4 = MicroBitPin(4)
813 | pin5 = MicroBitPin(5)
814 | pin6 = MicroBitPin(6)
815 | pin7 = MicroBitPin(7)
816 | pin8 = MicroBitPin(8)
817 | pin9 = MicroBitPin(9)
818 | pin10 = MicroBitPin(10)
819 | pin11 = MicroBitPin(11)
820 |
821 | pin13 = MicroBitPin(13)
822 | pin14 = MicroBitPin(14)
823 | pin15 = MicroBitPin(15)
824 | pin16 = MicroBitPin(16)
825 |
826 | pin19 = MicroBitPin(19)
827 | pin20 = MicroBitPin(20)
828 |
829 | def accelerometer_get_gestures():
830 | return (accelerometer.get_x(), accelerometer.get_y(), accelerometer.get_z())
831 |
832 | accelerometer.get_gestures = accelerometer_get_gestures
833 |
834 | try:
835 | from mpython import magnetic
836 | except ImportError as e:
837 | pass
838 | else:
839 | compass = magnetic
840 | compass.heading = magnetic.get_heading
841 |
842 | gc.collect()
843 |
844 |
--------------------------------------------------------------------------------
/library/qqai/README.md:
--------------------------------------------------------------------------------
1 | # qqai
2 |
3 | [腾讯AI](https://ai.qq.com/)开放平台的掌控板(mPython)、MicroPython API库。
4 |
5 | ## 依赖
6 |
7 | - `urequests`
8 | - `urllib.parse`
9 |
10 | ## 目前完成的功能
11 |
12 | - [ ] 机器视觉
13 | - [ ] OCR
14 | - [x] 通用OCR
15 | - [x] 行驶证驾驶证OCR
16 | - [x] 行驶证驾驶证OCR
17 | - [x] 手写体OCR
18 | - [x] 车牌OCR
19 | - [x] 名片OCR
20 | - [x] 银行卡OCR
21 | - [ ] 身份证OCR
22 | - [ ] 营业执照OCR
23 |
24 | - [ ] 人脸与人体识别
25 | - [ ] 人脸识别
26 | - [ ] 人脸检测与分析
27 | - [ ] 多人脸检测
28 | - [ ] 人脸对比
29 | - [ ] 跨年龄人脸识别
30 | - [ ] 五官定位
31 | - [ ] 人脸识别
32 | - [ ] 人脸验证
33 | - [ ] 个体管理
34 | - [ ] 个体创建
35 | - [ ] 删除个体
36 | - [ ] 增加人脸
37 | - [ ] 删除人脸
38 | - [ ] 设置信息
39 | - [ ] 获取信息
40 | - [ ] 信息查询
41 | - [ ] 获取组列表
42 | - [ ] 获取个体列表
43 | - [ ] 获取人脸列表
44 | - [ ] 获取人脸信息
45 |
46 | - [ ] 图片特效
47 | - [x] 人脸美妆
48 | - [x] 人脸变妆
49 | - [x] 滤镜
50 | - [x] 滤镜(天天P图)
51 | - [x] 滤镜(AI Lab)
52 | - [x] 人脸融合
53 | - [x] 大头贴
54 | - [x] 颜龄检测
55 |
56 | - [ ] 图片识别
57 | - [ ] 物体场景识别
58 | - [ ] 场景识别
59 | - [ ] 物体识别
60 | - [x] 图片标签识别
61 | - [x] 看图说话
62 | - [x] 模糊图片检测
63 | - [x] 美食图片识别
64 |
65 | - [x] 敏感信息审核
66 | - [x] 暴恐识别
67 | - [x] 图片鉴黄
68 |
69 | - [ ] 自然语言处理
70 | - [x] 智能闲聊
71 | - [x] 机器翻译
72 | - [x] 文本翻译
73 | - [x] 文本翻译(AI Lab)
74 | - [x] 文本翻译(翻译君)
75 | - [x] 图片翻译
76 | - [ ] 语音翻译
77 | - [x] 语种识别
78 | - [ ] 基础文本分析
79 | - [ ] 分词
80 | - [ ] 词性标注
81 | - [ ] 专有名词识别
82 | - [ ] 同义词识别
83 | - [ ] 语义解析
84 | - [ ] 意图成分识别
85 | - [ ] 情感分析
86 | - [ ] 情感分析识别
87 |
88 | - [ ] 智能语音
89 | - [ ] 语音识别
90 | - [x] 语音识别-echo版
91 | - [ ] 语音识别-流式版(AI Lab)
92 | - [ ] 语音识别-流式版(WeChat AI)
93 | - [ ] 长语音识别
94 | - [ ] 关键词检索
95 | - [ ] 语音合成
96 | - [x] 语音合成(AI Lab)
97 | - [ ] 语音合成(优图)
--------------------------------------------------------------------------------
/library/qqai/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ['nlp', 'aai', 'vision']
2 |
3 | from qqai.base import *
4 | import qqai.nlp
5 | import qqai.vision
6 | import qqai.aai
7 | from qqai import nlp ,aai, vision
8 |
--------------------------------------------------------------------------------
/library/qqai/aai.py:
--------------------------------------------------------------------------------
1 | from qqai.base import *
2 |
3 |
4 | class AAI(QQAIBase):
5 |
6 | def aai_asr(self, speech, format=2, rate=16000):
7 | """语音识别-echo版"""
8 | self.api = 'https://api.ai.qq.com/fcgi-bin/aai/aai_asr'
9 | self.params = {'app_id': self.app_id,
10 | 'time_stamp': self._time_stamp(),
11 | 'nonce_str': self._time_stamp(),
12 | 'format': format,
13 | 'rate': rate,
14 | 'speech': self.get_base64(speech)
15 | }
16 | self.params['sign'] = self.get_sign(self.params)
17 | s = self.call_api(self.params)
18 | contants = s.read()
19 | s.close()
20 | return json.loads(contants)
21 |
22 | def aai_tts(self, text, save_path ,speaker =1, format=3, volume=10, speed=100, aht=0, apc=58):
23 | """语音合成(AI Lab)"""
24 | self.api = 'https://api.ai.qq.com/fcgi-bin/aai/aai_tts'
25 | self.params = {'app_id': self.app_id,
26 | 'time_stamp': self._time_stamp(),
27 | 'nonce_str': self._time_stamp(),
28 | 'text': text,
29 | 'speaker': speaker,
30 | 'format': format,
31 | 'volume': volume,
32 | 'speed': speed,
33 | 'aht': aht,
34 | 'apc': apc
35 | }
36 | self.params['sign'] = self.get_sign(self.params)
37 | s = self.call_api(self.params)
38 | resp = self.response_base64_decode(s,b"\"speech\": \"",save_path)
39 | return resp
40 |
--------------------------------------------------------------------------------
/library/qqai/base.py:
--------------------------------------------------------------------------------
1 | from urllib import parse
2 | import hashlib
3 | import ubinascii
4 | import urequests
5 | import usocket
6 | import ussl
7 | import gc
8 | import time
9 | import os
10 | import sys
11 | import time
12 | import json
13 | sys.path.append('../')
14 |
15 |
16 | class QQAIBase:
17 | headers = {'Content-Type': 'application/x-www-form-urlencoded'}
18 |
19 | def __init__(self, app_id, app_key):
20 | self.app_id = app_id
21 | self.app_key = app_key
22 | self.params = {}
23 |
24 | def get_base64(self, media_path,save='.qqai_base64'):
25 | """获取媒体的Base64字符串
26 |
27 | :param media_param 媒体URL或文件路径
28 | """
29 | gc.collect()
30 | BLOCK_SZ = 1024 * 6
31 | with open(save, 'wb') as tmpfile:
32 | if type(media_path) == str:
33 | if 'https://' in media_path or 'http://' in media_path:
34 | rsp = urequests.get(media_path)
35 | while True:
36 | chunk_data = rsp.raw.read(BLOCK_SZ)
37 | if chunk_data:
38 | chunk_data = ubinascii.b2a_base64(
39 | chunk_data).strip()
40 | # print(chunk_data.decode(),end='')
41 | tmpfile.write(chunk_data)
42 | else:
43 | rsp.close()
44 | break
45 | else:
46 | with open(media_path, 'rb') as media_file:
47 | while True:
48 | chunk_data = media_file.read(BLOCK_SZ)
49 | if chunk_data:
50 | chunk_data = ubinascii.b2a_base64(
51 | chunk_data).strip()
52 | # print(chunk_data.decode(),end='')
53 | tmpfile.write(chunk_data)
54 | else:
55 | break
56 | else:
57 | raise TypeError('URL or file path must be str type')
58 | print("Base64 temporary files size: %0.3fKB" %
59 | (os.stat(save)[6]//1000))
60 | return tmpfile
61 |
62 | def get_sign(self, params):
63 | """获取签名"""
64 | gc.collect()
65 | uri_str = ''
66 | BLOCK_SZ = 1024*3
67 | # print("sign_str: ",end='')
68 | hash_str = hashlib.md5()
69 | for key in sorted(params.keys()):
70 | if not hasattr(params[key], 'read'):
71 | uri_str = '{}={}&'.format(
72 | key, parse.quote_plus(str(params[key]), safe=''))
73 | hash_str.update(uri_str)
74 | # print(uri_str,end='')
75 | else:
76 | uri_str = '{}=' .format(key)
77 | hash_str.update(uri_str)
78 | # print(uri_str,end='')
79 | with open('.qqai_base64', 'r') as file_base64:
80 | while True:
81 | chunk_data = file_base64.read(BLOCK_SZ)
82 | if chunk_data:
83 | uri_str = parse.quote_plus(chunk_data, safe='')
84 | hash_str.update(uri_str)
85 | # print(uri_str,end='')
86 | else:
87 | break
88 | hash_str.update('&')
89 | # print('&',end='')
90 | uri_str = 'app_key='+self.app_key
91 | hash_str.update(uri_str)
92 | # print(uri_str)
93 | return ubinascii.hexlify(hash_str.digest()).decode().upper()
94 |
95 | def call_api(self, params, api=None):
96 | gc.collect()
97 | if api is None:
98 | api = self.api
99 | rsp = self._qqai_post(api, params)
100 | gc.collect()
101 | return rsp
102 |
103 | def _time_stamp(self):
104 | return str(time.time() + 946656001)
105 |
106 | def _qqai_post(self, url, params):
107 | gc.collect()
108 | port = 443
109 | proto, dummy, host, path = url.split("/", 3)
110 | ai = usocket.getaddrinfo(host, port)
111 | # print(ai)
112 | addr = ai[0][4]
113 | s = usocket.socket()
114 | s.connect(addr)
115 | s = ussl.wrap_socket(s)
116 | s.write(b"%s /%s HTTP/1.0\r\n" % ('POST', path))
117 | s.write(b"Host: %s\r\n" % host)
118 | s.write(b"Connection: keep-alive\r\n")
119 | s.write(b"Content-Type: application/x-www-form-urlencoded\r\n")
120 | s.write(b"Transfer-Encoding: chunked\r\n")
121 |
122 | s.write(b"\r\n")
123 | temp_str = ''
124 | list_key = list(params.keys())
125 | for k in list_key:
126 | if not hasattr(params[k], 'read'):
127 | temp_str = k+'='+parse.quote_plus(str(params[k]), safe='')
128 | if k is not list_key[-1]:
129 | temp_str = temp_str + '&'
130 |
131 | chunk_size = hex(len(temp_str))[2:]
132 | s.write(chunk_size.encode())
133 | # print(chunk_size,end='')
134 | s.write(b'\r\n')
135 | # print()
136 | s.write(temp_str.encode())
137 | # print(temp_str,end='')
138 | s.write(b'\r\n')
139 | # print()
140 |
141 | else:
142 | temp_str = k+'='
143 | chunk_size = hex(len(temp_str))[2:]
144 | s.write(chunk_size.encode())
145 | s.write(b'\r\n')
146 | # print(chunk_size)
147 | s.write(temp_str.encode())
148 | s.write(b'\r\n')
149 | # print(temp_str)
150 | with open('.qqai_base64', 'r') as file_base64:
151 | while True:
152 | temp_str = file_base64.read(1024*3)
153 | if temp_str:
154 | temp_str = parse.quote_plus(temp_str, safe='')
155 | chunk_size = hex(len(temp_str))[2:]
156 | s.write((chunk_size+'\r\n').encode())
157 | # print(chunk_size)
158 | s.write((temp_str+'\r\n').encode())
159 | # print(temp_str)
160 | else:
161 | break
162 | if k is not list_key[-1]:
163 | s.write(b'1\r\n')
164 | # print('1')
165 | s.write(b'&\r\n')
166 | # print('&')
167 | # chunked end
168 | s.write(b'0\r\n')
169 | # print('0')
170 | s.write(b'\r\n')
171 | # print('')
172 |
173 | l = s.readline()
174 | protover, status, msg = l.split(None, 2)
175 | # print(protover, status, msg)
176 | status = int(status)
177 | while True:
178 | l = s.readline()
179 | # print(l)
180 | if not l or l == b"\r\n":
181 | break
182 | return s
183 |
184 | def response_base64_decode(self, socket, key_str, path):
185 | gc.collect()
186 | _socket = socket
187 | BlOCK_SZ = 512*4
188 | chunked = _socket.read(1024)
189 | if len(chunked) < 1024 and chunked[-1:] == b'\n':
190 | _socket.close()
191 | return json.loads(chunked.decode())
192 | # print(json.loads(chunked.decode()))
193 | else:
194 | with open(path, 'wb') as file_image:
195 | chunked = chunked.replace(b'\\', b'')
196 | index = chunked.find(key_str)
197 | if index != -1:
198 | chunked = chunked[index+len(key_str):]
199 | while (BlOCK_SZ-len(chunked)) != 0:
200 | miss_len = BlOCK_SZ-len(chunked)
201 | miss_str = _socket.read(miss_len).replace(b'\\', b'')
202 | chunked = chunked+miss_str
203 | # print(chunked.decode(),end='')
204 | file_image.write(ubinascii.a2b_base64(chunked))
205 | while True:
206 | chunked = _socket.read(BlOCK_SZ).replace(b'\\', b'')
207 | while (BlOCK_SZ-len(chunked)) != 0:
208 | miss_len = BlOCK_SZ-len(chunked)
209 | miss_str = _socket.read(miss_len).replace(b'\\', b'')
210 | chunked = chunked+miss_str
211 | index_end = chunked.find(b"\"")
212 | if index_end != -1:
213 | chunked = chunked[:index_end]
214 | # print(chunked.decode(),end='')
215 | file_image.write(ubinascii.a2b_base64(chunked))
216 | _socket.close()
217 | return True
218 | # print(chunked.decode(),end='')
219 | file_image.write(ubinascii.a2b_base64(chunked))
220 |
--------------------------------------------------------------------------------
/library/qqai/nlp.py:
--------------------------------------------------------------------------------
1 | from qqai.base import *
2 |
3 | class Nlp(QQAIBase):
4 | """自然语言"""
5 |
6 | def text_translate_ailab(self,text,type=0):
7 | """文本翻译(AI Lab)"""
8 | self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_texttrans'
9 |
10 | self.params = {'app_id': self.app_id,
11 | 'time_stamp': self._time_stamp(),
12 | 'nonce_str': self._time_stamp(),
13 | 'type': type,
14 | 'text': text,
15 | }
16 | self.params['sign'] = self.get_sign(self.params)
17 | s = self.call_api(self.params)
18 | contants = s.read()
19 | s.close()
20 | return json.loads(contants)
21 |
22 |
23 | def text_translate_fanyi(self,text,source='auto', target='en'):
24 | """文本翻译(翻译君)"""
25 | self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_texttranslate'
26 | self.params = {'app_id': self.app_id,
27 | 'time_stamp': self._time_stamp(),
28 | 'nonce_str': self._time_stamp(),
29 | 'text': text,
30 | 'source': source,
31 | 'target': target,
32 | }
33 | self.params['sign'] = self.get_sign(self.params)
34 | s = self.call_api(self.params)
35 | contants = s.read()
36 | s.close()
37 | return json.loads(contants)
38 |
39 | def text_detect(self, text,candidate_langs=None, force=0):
40 | """语种识别"""
41 | self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_textdetect'
42 | if candidate_langs is None:
43 | candidate_langs = ['zh', 'en', 'jp', 'kr']
44 | if type(candidate_langs) == str:
45 | candidate_langs_param = candidate_langs
46 | else:
47 | candidate_langs_param = '|'.join(candidate_langs)
48 | self.params = {'app_id': self.app_id,
49 | 'time_stamp': self._time_stamp(),
50 | 'nonce_str': self._time_stamp(),
51 | 'text': text,
52 | 'candidate_langs': candidate_langs_param,
53 | 'force': force
54 | }
55 | self.params['sign'] = self.get_sign(self.params)
56 | s = self.call_api(self.params)
57 | contants = s.read()
58 | s.close()
59 | return json.loads(contants)
60 |
61 |
62 |
63 | def image_translate(self,image_path, scene='doc', source='auto', target='auto'):
64 | """图片翻译"""
65 | self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_imagetranslate'
66 | self.params = {'app_id': self.app_id,
67 | 'time_stamp': self._time_stamp(),
68 | 'nonce_str': self._time_stamp(),
69 | 'image': self.get_base64(image_path),
70 | 'session_id': self._time_stamp(),
71 | 'scene': scene,
72 | 'source': source,
73 | 'target': target,
74 | }
75 | self.params['sign'] = self.get_sign(self.params)
76 | s = self.call_api(self.params)
77 | contants = s.read()
78 | s.close()
79 | return json.loads(contants)
80 |
81 | def text_chat(self,question):
82 | """图片翻译"""
83 | self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_textchat'
84 | self.params = {'app_id': self.app_id,
85 | 'time_stamp': self._time_stamp(),
86 | 'nonce_str': self._time_stamp(),
87 | 'session': self._time_stamp(),
88 | 'question': question
89 | }
90 | self.params['sign'] = self.get_sign(self.params)
91 | s = self.call_api(self.params)
92 | contants = s.read()
93 | s.close()
94 | return json.loads(contants)
95 |
96 | # class Text(QQAIBase):
97 | # """基础文本分析"""
98 |
99 | # def word_seg(self, text):
100 | # """"分词"""
101 | # self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordseg'
102 | # self.params = {'app_id': self.app_id,
103 | # 'time_stamp': self._time_stamp(),
104 | # 'nonce_str': self._time_stamp(),
105 | # 'text': text
106 | # }
107 | # self.params['sign'] = self.get_sign(self.params)
108 | # s = self.call_api(self.params)
109 | # contants = s.read()
110 | # s.close()
111 | # return json.loads(contants)
112 |
113 | # def word_pos(self, text):
114 | # """"词性标注"""
115 | # self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordpos'
116 | # self.params = {'app_id': self.app_id,
117 | # 'time_stamp': self._time_stamp(),
118 | # 'nonce_str': self._time_stamp(),
119 | # 'text': text
120 | # }
121 | # self.params['sign'] = self.get_sign(self.params)
122 | # s = self.call_api(self.params)
123 | # contants = s.read()
124 | # s.close()
125 | # return json.loads(contants)
126 |
127 | # def word_ner(self, text):
128 | # """"专有名词识别"""
129 | # self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordner'
130 | # self.params = {'app_id': self.app_id,
131 | # 'time_stamp': self._time_stamp(),
132 | # 'nonce_str': self._time_stamp(),
133 | # 'text': text
134 | # }
135 | # self.params['sign'] = self.get_sign(self.params)
136 | # s = self.call_api(self.params)
137 | # contants = s.read()
138 | # s.close()
139 | # return json.loads(contants)
140 |
141 | # def word_syn(self, text):
142 | # """"同义词识别"""
143 | # self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordsyn'
144 | # self.params = {'app_id': self.app_id,
145 | # 'time_stamp': self._time_stamp(),
146 | # 'nonce_str': self._time_stamp(),
147 | # 'text': text
148 | # }
149 | # self.params['sign'] = self.get_sign(self.params)
150 | # s = self.call_api(self.params)
151 | # contants = s.read()
152 | # s.close()
153 | # return json.loads(contants)
154 |
155 | # def word_com(self, text):
156 | # """"意图成分识别"""
157 | # self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_wordcom'
158 | # self.params = {'app_id': self.app_id,
159 | # 'time_stamp': self._time_stamp(),
160 | # 'nonce_str': self._time_stamp(),
161 | # 'text': text
162 | # }
163 | # self.params['sign'] = self.get_sign(self.params)
164 | # s = self.call_api(self.params)
165 | # contants = s.read()
166 | # s.close()
167 | # return json.loads(contants)
168 |
169 | # def text_polar(self, text):
170 | # """"情感分析识别"""
171 | # self.api = 'https://api.ai.qq.com/fcgi-bin/nlp/nlp_textpolar'
172 | # self.params = {'app_id': self.app_id,
173 | # 'time_stamp': self._time_stamp(),
174 | # 'nonce_str': self._time_stamp(),
175 | # 'text': text
176 | # }
177 | # self.params['sign'] = self.get_sign(self.params)
178 | # s = self.call_api(self.params)
179 | # contants = s.read()
180 | # s.close()
181 | # return json.loads(contants)
182 |
183 |
184 |
--------------------------------------------------------------------------------
/library/qqai/vision/__init__.py:
--------------------------------------------------------------------------------
1 | __all__ = ['picture', 'ocr', 'face']
2 |
3 | from qqai.vision import picture, ocr, face
--------------------------------------------------------------------------------
/library/qqai/vision/face.py:
--------------------------------------------------------------------------------
1 | from qqai.base import *
2 |
3 | class Face(QQAIBase):
4 |
5 | def detect_face(self,image,mode=1):
6 | """人脸检测与分析"""
7 | self.api = 'https://api.ai.qq.com/fcgi-bin/face/face_detectface'
8 | self.params = {'app_id': self.app_id,
9 | 'time_stamp': self._time_stamp(),
10 | 'nonce_str': self._time_stamp(),
11 | 'mode': mode,
12 | 'image': self.get_base64(image)
13 | }
14 | self.params['sign'] = self.get_sign(self.params)
15 | s = self.call_api(self.params)
16 | contants = s.read()
17 | s.close()
18 | return json.loads(contants)
19 |
--------------------------------------------------------------------------------
/library/qqai/vision/ocr.py:
--------------------------------------------------------------------------------
1 | from qqai.base import *
2 |
3 | class OCR(QQAIBase):
4 |
5 | def general_ocr(self,image):
6 | """通用OCR"""
7 | self.api = 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_generalocr'
8 |
9 | self.params = {'app_id': self.app_id,
10 | 'time_stamp': self._time_stamp(),
11 | 'nonce_str': self._time_stamp(),
12 | 'image': self.get_base64(image)
13 | }
14 | self.params['sign'] = self.get_sign(self.params)
15 | s = self.call_api(self.params)
16 | contants = s.read()
17 | s.close()
18 | return json.loads(contants)
19 |
20 | def driverlicense_ocr(self,image,type):
21 | """行驶证驾驶证OCR"""
22 | self.api = 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_driverlicenseocr'
23 |
24 | self.params = {'app_id': self.app_id,
25 | 'time_stamp': self._time_stamp(),
26 | 'nonce_str': self._time_stamp(),
27 | 'image': self.get_base64(image),
28 | 'type': type
29 | }
30 | self.params['sign'] = self.get_sign(self.params)
31 | s = self.call_api(self.params)
32 | contants = s.read()
33 | s.close()
34 | return json.loads(contants)
35 |
36 | def handwriting_ocr(self,image):
37 | """手写体OCR"""
38 | self.api = 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_handwritingocr'
39 |
40 | self.params = {'app_id': self.app_id,
41 | 'time_stamp': self._time_stamp(),
42 | 'nonce_str': self._time_stamp(),
43 | 'image': self.get_base64(image),
44 | }
45 | self.params['sign'] = self.get_sign(self.params)
46 | s = self.call_api(self.params)
47 | contants = s.read()
48 | s.close()
49 | return json.loads(contants)
50 |
51 | def plate_ocr(self,image):
52 | """车牌OCR"""
53 | self.api = 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_plateocr'
54 |
55 | self.params = {'app_id': self.app_id,
56 | 'time_stamp': self._time_stamp(),
57 | 'nonce_str': self._time_stamp(),
58 | 'image': self.get_base64(image),
59 | }
60 | self.params['sign'] = self.get_sign(self.params)
61 | s = self.call_api(self.params)
62 | contants = s.read()
63 | s.close()
64 | return json.loads(contants)
65 |
66 | def bc_ocr(self,image):
67 | """名片OCR"""
68 | self.api = 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_bcocr'
69 |
70 | self.params = {'app_id': self.app_id,
71 | 'time_stamp': self._time_stamp(),
72 | 'nonce_str': self._time_stamp(),
73 | 'image': self.get_base64(image),
74 | }
75 | self.params['sign'] = self.get_sign(self.params)
76 | s = self.call_api(self.params)
77 | contants = s.read()
78 | s.close()
79 | return json.loads(contants)
80 |
81 | def creditcard_ocr(self,image):
82 | """银行卡OCR"""
83 | self.api = 'https://api.ai.qq.com/fcgi-bin/ocr/ocr_creditcardocr'
84 |
85 | self.params = {'app_id': self.app_id,
86 | 'time_stamp': self._time_stamp(),
87 | 'nonce_str': self._time_stamp(),
88 | 'image': self.get_base64(image),
89 | }
90 | self.params['sign'] = self.get_sign(self.params)
91 | s = self.call_api(self.params)
92 | contants = s.read()
93 | s.close()
94 | return json.loads(contants)
95 |
96 |
97 |
--------------------------------------------------------------------------------
/library/qqai/vision/picture.py:
--------------------------------------------------------------------------------
1 | from qqai.base import *
2 |
3 | class Picture(QQAIBase):
4 |
5 | def imagetotext(self,image):
6 | """看图说话"""
7 | self.api = 'https://api.ai.qq.com/fcgi-bin/vision/vision_imgtotext'
8 |
9 | self.params = {'app_id': self.app_id,
10 | 'session_id': self._time_stamp(),
11 | 'time_stamp': self._time_stamp(),
12 | 'nonce_str': self._time_stamp(),
13 | 'image': self.get_base64(image)
14 | }
15 | self.params['sign'] = self.get_sign(self.params)
16 | s = self.call_api(self.params)
17 | contants = s.read()
18 | s.close()
19 | return json.loads(contants)
20 |
21 | def image_tag(self,image):
22 | """多标签识别"""
23 | self.api = 'https://api.ai.qq.com/fcgi-bin/image/image_tag'
24 |
25 | self.params = {'app_id': self.app_id,
26 | 'time_stamp': self._time_stamp(),
27 | 'nonce_str': self._time_stamp(),
28 | 'image': self.get_base64(image)
29 | }
30 | self.params['sign'] = self.get_sign(self.params)
31 | s = self.call_api(self.params)
32 | contants = s.read()
33 | s.close()
34 | return json.loads(contants)
35 |
36 | def isfuzzy(self,image):
37 | """模糊图片检测"""
38 | self.api = 'https://api.ai.qq.com/fcgi-bin/image/image_fuzzy'
39 |
40 | self.params = {'app_id': self.app_id,
41 | 'time_stamp': self._time_stamp(),
42 | 'nonce_str': self._time_stamp(),
43 | 'image': self.get_base64(image)
44 | }
45 | self.params['sign'] = self.get_sign(self.params)
46 | s = self.call_api(self.params)
47 | contants = s.read()
48 | s.close()
49 | return json.loads(contants)
50 | def isfood(self,image):
51 | """美食图片识别"""
52 | self.api = 'https://api.ai.qq.com/fcgi-bin/image/image_food'
53 |
54 | self.params = {'app_id': self.app_id,
55 | 'time_stamp': self._time_stamp(),
56 | 'nonce_str': self._time_stamp(),
57 | 'image': self.get_base64(image)
58 | }
59 | self.params['sign'] = self.get_sign(self.params)
60 | s = self.call_api(self.params)
61 | contants = s.read()
62 | s.close()
63 | return json.loads(contants)
64 |
65 | # def scener_recog(self,image,topk=5,farmat=1):
66 | # """场景识别 (调试不能使用)"""
67 | # self.api = 'https://api.ai.qq.com/fcgi-bin/vision/vision_scener'
68 |
69 | # self.params = {'app_id': self.app_id,
70 | # 'time_stamp': self._time_stamp(),
71 | # 'nonce_str': self._time_stamp(),
72 | # 'format': farmat ,
73 | # 'topk': topk ,
74 | # 'image': self.get_base64(image)
75 | # }
76 | # self.params['sign'] = self.get_sign(self.params)
77 | # s = self.call_api(self.params)
78 | # contants = s.read()
79 | # s.close()
80 | # return json.loads(contants)
81 |
82 | # def object_recog(self,image,topk=5,farmat=1):
83 | # """物体识别 (调试不能使用)"""
84 | # self.api = 'https://api.ai.qq.com/fcgi-bin/vision/vision_objectr'
85 |
86 | # self.params = {'app_id': self.app_id,
87 | # 'time_stamp': self._time_stamp(),
88 | # 'nonce_str': self._time_stamp(),
89 | # 'format': farmat ,
90 | # 'topk': topk ,
91 | # 'image': self.get_base64(image)
92 | # }
93 | # self.params['sign'] = self.get_sign(self.params)
94 | # s = self.call_api(self.params)
95 | # contants = s.read()
96 | # s.close()
97 | # return json.loads(contants)
98 |
99 | def terrorism(self,image):
100 | """暴恐图片识别"""
101 | self.api = 'https://api.ai.qq.com/fcgi-bin/image/image_terrorism'
102 |
103 | self.params = {'app_id': self.app_id,
104 | 'time_stamp': self._time_stamp(),
105 | 'nonce_str': self._time_stamp(),
106 | 'image': self.get_base64(image)
107 | }
108 | self.params['sign'] = self.get_sign(self.params)
109 | s = self.call_api(self.params)
110 | contants = s.read()
111 | s.close()
112 | return json.loads(contants)
113 |
114 | def porn(self,image):
115 | """智能鉴黄"""
116 | self.api = 'https://api.ai.qq.com/fcgi-bin/vision/vision_porn'
117 | self.params = {'app_id': self.app_id,
118 | 'time_stamp': self._time_stamp(),
119 | 'nonce_str': self._time_stamp(),
120 | 'image': self.get_base64(image)
121 | }
122 | self.params['sign'] = self.get_sign(self.params)
123 | s = self.call_api(self.params)
124 | contants = s.read()
125 | s.close()
126 | return json.loads(contants)
127 |
128 | def image_filter_ptu(self,image, save_path,filter=1):
129 | """图片滤镜(天天P图)"""
130 | self.api = 'https://api.ai.qq.com/fcgi-bin/ptu/ptu_imgfilter'
131 | self.params = {'app_id': self.app_id,
132 | 'time_stamp': self._time_stamp(),
133 | 'nonce_str': self._time_stamp(),
134 | 'filter': filter,
135 | 'image': self.get_base64(image)
136 | }
137 | self.params['sign'] = self.get_sign(self.params)
138 | s = self.call_api(self.params)
139 | resp = self.response_base64_decode(s,b"\"image\": \"", save_path)
140 | return resp
141 |
142 | def image_filter_ailab(self,image, save_path,filter=1):
143 | """图片滤镜(AI Lab)"""
144 | self.api = 'https://api.ai.qq.com/fcgi-bin/vision/vision_imgfilter'
145 | self.params = {'app_id': self.app_id,
146 | 'time_stamp': self._time_stamp(),
147 | 'nonce_str': self._time_stamp(),
148 | 'session_id': self._time_stamp(),
149 | 'filter': filter,
150 | 'image': self.get_base64(image)
151 | }
152 | self.params['sign'] = self.get_sign(self.params)
153 | s = self.call_api(self.params)
154 | resp = self.response_base64_decode(s,b"\"image\": \"", save_path)
155 | return resp
156 |
157 | def face_cosmetic(self,image, save_path,cosmetic=1):
158 | """人脸美妆"""
159 | self.api = 'https://api.ai.qq.com/fcgi-bin/ptu/ptu_facecosmetic'
160 | self.params = {'app_id': self.app_id,
161 | 'time_stamp': self._time_stamp(),
162 | 'nonce_str': self._time_stamp(),
163 | 'cosmetic': cosmetic,
164 | 'image': self.get_base64(image)
165 | }
166 | self.params['sign'] = self.get_sign(self.params)
167 | s = self.call_api(self.params)
168 | resp = self.response_base64_decode(s,b"\"image\": \"", save_path)
169 | return resp
170 |
171 | def face_decoration(self,image, save_path,decoration=1):
172 | """人脸变妆"""
173 | self.api = 'https://api.ai.qq.com/fcgi-bin/ptu/ptu_facedecoration'
174 | self.params = {'app_id': self.app_id,
175 | 'time_stamp': self._time_stamp(),
176 | 'nonce_str': self._time_stamp(),
177 | 'decoration': decoration,
178 | 'image': self.get_base64(image)
179 | }
180 | self.params['sign'] = self.get_sign(self.params)
181 | s = self.call_api(self.params)
182 | resp = self.response_base64_decode(s,b"\"image\": \"", save_path)
183 | return resp
184 |
185 | def face_sticker(self,image, save_path,sticker=1):
186 | """大头贴"""
187 | self.api = 'https://api.ai.qq.com/fcgi-bin/ptu/ptu_facesticker'
188 | self.params = {'app_id': self.app_id,
189 | 'time_stamp': self._time_stamp(),
190 | 'nonce_str': self._time_stamp(),
191 | 'sticker': sticker,
192 | 'image': self.get_base64(image)
193 | }
194 | self.params['sign'] = self.get_sign(self.params)
195 | s = self.call_api(self.params)
196 | resp = self.response_base64_decode(s,b"\"image\": \"", save_path)
197 | return resp
198 |
199 |
--------------------------------------------------------------------------------
/library/urllib/README.md:
--------------------------------------------------------------------------------
1 |
2 | 用于URL编码,裁剪于[MicroPython-lib@urllib.parse](https://github.com/micropython/micropython-lib/tree/master/urllib.parse)
3 |
4 | 保留以下函数:
5 | - quote
6 | - quote_from_bytes
7 | - urlencode
8 | - quote_plus
--------------------------------------------------------------------------------
/library/urllib/parse.py:
--------------------------------------------------------------------------------
1 |
2 | """
3 | urllib.paese simplified version
4 | fork by Micropython-lib
5 |
6 | MIT license; Copyright (c) 2019 tangliufeng@LabPlus
7 | """
8 |
9 |
10 | class defaultdict:
11 |
12 | @staticmethod
13 | def __new__(cls, default_factory=None, **kwargs):
14 | # Some code (e.g. urllib.urlparse) expects that basic defaultdict
15 | # functionality will be available to subclasses without them
16 | # calling __init__().
17 | self = super(defaultdict, cls).__new__(cls)
18 | self.d = {}
19 | return self
20 |
21 | def __init__(self, default_factory=None, **kwargs):
22 | self.d = kwargs
23 | self.default_factory = default_factory
24 |
25 | def __getitem__(self, key):
26 | try:
27 | return self.d[key]
28 | except KeyError:
29 | v = self.__missing__(key)
30 | self.d[key] = v
31 | return v
32 |
33 | def __setitem__(self, key, v):
34 | self.d[key] = v
35 |
36 | def __delitem__(self, key):
37 | del self.d[key]
38 |
39 | def __contains__(self, key):
40 | return key in self.d
41 |
42 | def __missing__(self, key):
43 | if self.default_factory is None:
44 | raise KeyError(key)
45 | return self.default_factory()
46 |
47 |
48 |
49 | class Quoter(defaultdict):
50 | """A mapping from bytes (in range(0,256)) to strings.
51 |
52 | String values are percent-encoded byte values, unless the key < 128, and
53 | in the "safe" set (either the specified safe set, or default set).
54 | """
55 | # Keeps a cache internally, using defaultdict, for efficiency (lookups
56 | # of cached keys don't call Python code at all).
57 | def __init__(self, safe):
58 | """safe: bytes object."""
59 | self.safe = _ALWAYS_SAFE.union(safe)
60 |
61 | def __repr__(self):
62 | # Without this, will just display as a defaultdict
63 | return "" % dict(self)
64 |
65 | def __missing__(self, b):
66 | # Handle a cache miss. Store quoted string in cache and return.
67 | res = chr(b) if b in self.safe else '%{:02X}'.format(b)
68 | self[b] = res
69 | return res
70 |
71 |
72 |
73 | def quote_plus(string, safe='', encoding=None, errors=None):
74 | """Like quote(), but also replace ' ' with '+', as required for quoting
75 | HTML form values. Plus signs in the original string are escaped unless
76 | they are included in safe. It also does not have safe default to '/'.
77 | """
78 | # Check if ' ' in string, where string may either be a str or bytes. If
79 | # there are no spaces, the regular quote will produce the right answer.
80 | if ((isinstance(string, str) and ' ' not in string) or
81 | (isinstance(string, bytes) and b' ' not in string)):
82 | return quote(string, safe, encoding, errors)
83 | if isinstance(safe, str):
84 | space = ' '
85 | else:
86 | space = b' '
87 | string = quote(string, safe + space, encoding, errors)
88 | return string.replace(' ', '+')
89 |
90 | _ALWAYS_SAFE = frozenset(b'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
91 | b'abcdefghijklmnopqrstuvwxyz'
92 | b'0123456789'
93 | b'_.-')
94 | _ALWAYS_SAFE_BYTES = bytes(_ALWAYS_SAFE)
95 | _safe_quoters = {}
96 |
97 | def quote(string, safe='/', encoding=None, errors=None):
98 | """quote('abc def') -> 'abc%20def'
99 |
100 | Each part of a URL, e.g. the path info, the query, etc., has a
101 | different set of reserved characters that must be quoted.
102 |
103 | RFC 2396 Uniform Resource Identifiers (URI): Generic Syntax lists
104 | the following reserved characters.
105 |
106 | reserved = ";" | "/" | "?" | ":" | "@" | "&" | "=" | "+" |
107 | "$" | ","
108 |
109 | Each of these characters is reserved in some component of a URL,
110 | but not necessarily in all of them.
111 |
112 | By default, the quote function is intended for quoting the path
113 | section of a URL. Thus, it will not encode '/'. This character
114 | is reserved, but in typical usage the quote function is being
115 | called on a path where the existing slash characters are used as
116 | reserved characters.
117 |
118 | string and safe may be either str or bytes objects. encoding must
119 | not be specified if string is a str.
120 |
121 | The optional encoding and errors parameters specify how to deal with
122 | non-ASCII characters, as accepted by the str.encode method.
123 | By default, encoding='utf-8' (characters are encoded with UTF-8), and
124 | errors='strict' (unsupported characters raise a UnicodeEncodeError).
125 | """
126 | if isinstance(string, str):
127 | if not string:
128 | return string
129 | if encoding is None:
130 | encoding = 'utf-8'
131 | if errors is None:
132 | errors = 'strict'
133 | string = string.encode(encoding, errors)
134 | else:
135 | if encoding is not None:
136 | raise TypeError("quote() doesn't support 'encoding' for bytes")
137 | if errors is not None:
138 | raise TypeError("quote() doesn't support 'errors' for bytes")
139 | return quote_from_bytes(string, safe)
140 |
141 |
142 | def quote_from_bytes(bs, safe='/'):
143 | """Like quote(), but accepts a bytes object rather than a str, and does
144 | not perform string-to-bytes encoding. It always returns an ASCII string.
145 | quote_from_bytes(b'abc def\x3f') -> 'abc%20def%3f'
146 | """
147 | if not isinstance(bs, (bytes, bytearray)):
148 | raise TypeError("quote_from_bytes() expected bytes")
149 | if not bs:
150 | return ''
151 | if isinstance(safe, str):
152 | # Normalize 'safe' by converting to bytes and removing non-ASCII chars
153 | safe = safe.encode('ascii', 'ignore')
154 | else:
155 | safe = bytes([c for c in safe if c < 128])
156 | if not bs.rstrip(_ALWAYS_SAFE_BYTES + safe):
157 | return bs.decode()
158 | try:
159 | quoter = _safe_quoters[safe]
160 | except KeyError:
161 | _safe_quoters[safe] = quoter = Quoter(safe).__getitem__
162 | return ''.join([quoter(char) for char in bs])
163 |
164 | def urlencode(query, doseq=False, safe='', encoding=None, errors=None):
165 | """Encode a dict or sequence of two-element tuples into a URL query string.
166 |
167 | If any values in the query arg are sequences and doseq is true, each
168 | sequence element is converted to a separate parameter.
169 |
170 | If the query arg is a sequence of two-element tuples, the order of the
171 | parameters in the output will match the order of parameters in the
172 | input.
173 |
174 | The components of a query arg may each be either a string or a bytes type.
175 | When a component is a string, the safe, encoding and error parameters are
176 | sent to the quote_plus function for encoding.
177 | """
178 |
179 | if hasattr(query, "items"):
180 | query = query.items()
181 | else:
182 | # It's a bother at times that strings and string-like objects are
183 | # sequences.
184 | try:
185 | # non-sequence items should not work with len()
186 | # non-empty strings will fail this
187 | if len(query) and not isinstance(query[0], tuple):
188 | raise TypeError
189 | # Zero-length sequences of all types will get here and succeed,
190 | # but that's a minor nit. Since the original implementation
191 | # allowed empty dicts that type of behavior probably should be
192 | # preserved for consistency
193 | except TypeError:
194 | # ty, va, tb = sys.exc_info()
195 | raise TypeError("not a valid non-string sequence "
196 | "or mapping object")#.with_traceback(tb)
197 |
198 | l = []
199 | if not doseq:
200 | for k, v in query:
201 | if isinstance(k, bytes):
202 | k = quote_plus(k, safe)
203 | else:
204 | k = quote_plus(str(k), safe, encoding, errors)
205 |
206 | if isinstance(v, bytes):
207 | v = quote_plus(v, safe)
208 | else:
209 | v = quote_plus(str(v), safe, encoding, errors)
210 | l.append(k + '=' + v)
211 | else:
212 | for k, v in query:
213 | if isinstance(k, bytes):
214 | k = quote_plus(k, safe)
215 | else:
216 | k = quote_plus(str(k), safe, encoding, errors)
217 |
218 | if isinstance(v, bytes):
219 | v = quote_plus(v, safe)
220 | l.append(k + '=' + v)
221 | elif isinstance(v, str):
222 | v = quote_plus(v, safe, encoding, errors)
223 | l.append(k + '=' + v)
224 | else:
225 | try:
226 | # Is this a sufficient test for sequence-ness?
227 | x = len(v)
228 | except TypeError:
229 | # not a sequence
230 | v = quote_plus(str(v), safe, encoding, errors)
231 | l.append(k + '=' + v)
232 | else:
233 | # loop over the sequence
234 | for elt in v:
235 | if isinstance(elt, bytes):
236 | elt = quote_plus(elt, safe)
237 | else:
238 | elt = quote_plus(str(elt), safe, encoding, errors)
239 | l.append(k + '=' + elt)
240 | return '&'.join(l)
--------------------------------------------------------------------------------
/library/yeelight/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 labplus
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/library/yeelight/MANIFEST:
--------------------------------------------------------------------------------
1 | # file GENERATED by distutils, do NOT edit
2 | README.md
3 | setup.cfg
4 | setup.py
5 |
--------------------------------------------------------------------------------
/library/yeelight/MANIFEST.in:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/yeelight/MANIFEST.in
--------------------------------------------------------------------------------
/library/yeelight/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## 概述
4 |
5 | `yeelight` 是掌控板或micropython驱动库,用于控制局域网内的YeeLight智能灯泡/小米智能灯具设备。
6 |
7 | ## 库的安装方法
8 |
9 | 可通过以下任一方法进行安装。
10 | 1. 将项目中的`yeelight.py`
11 | 2. 在掌控板REPL界面中,使用upip安装,步骤如下:
12 | * 前置条件需要掌控板连接网络
13 | * 导入upip模块,执行`import upip`
14 | * 执行`upip.install('mPython-yeelight')
15 |
16 | ```python
17 | >>> import upip
18 | >>> upip.install('mPython-yeelight')
19 | ```
20 |
21 | ## 使用
22 |
23 | 准备工作:
24 |
25 | * YeeLight智能灯泡在使用前,须要先配置好连接好wifi,并将 `局域网控制` 功能打开。
26 | * 掌控板确保已与智能灯泡在同个局域网内,并网络通畅。
27 |
28 | yeelight Library Documentation:https://mpython-lib.readthedocs.io
29 |
30 | YeeLight第三方控制协议:https://www.yeelight.com/download/Yeelight_Inter-Operation_Spec.pdf
31 |
32 | ## 简单示例
33 |
34 | ```python
35 | from mpython import *
36 | from yeelight import *
37 |
38 | my_wifi = wifi() # 连接到与YeeLight相同的局域网内
39 | my_wifi.connectWiFi("","")
40 |
41 |
42 | discover_bulbs() # 发现局域网内YeeLight的设备信息
43 |
44 | bulb=Bulb("192.168.0.7") # 构建Bulb类用于控制,传入IP参数
45 |
46 | bulb.turn_on() # 开灯
47 | sleep(2)
48 | bulb.turn_off() # 关灯
49 | sleep(2)
50 | bulb.toggle() # 翻转
51 | sleep(2)
52 | bulb.set_rgb(255,0,0) # 设置RGB值
53 | bulb.set_brightness(50) # 调节亮度
54 | sleep(2)
55 | bulb.set_hsv(180,100) # 设置HSV值
56 | sleep(2)
57 | ```
58 |
59 | ## 执照
60 |
61 | 所有代码均在MIT许可下发布。
--------------------------------------------------------------------------------
/library/yeelight/examples/yeelight_simple.py:
--------------------------------------------------------------------------------
1 | from mpython import *
2 | from yeelight import *
3 |
4 | my_wifi = wifi() # 连接到与YeeLight相同的局域网内
5 | my_wifi.connectWiFi("","")
6 |
7 |
8 | discover_bulbs() # 发现局域网内YeeLight的设备信息
9 |
10 | bulb=Bulb("192.168.0.7") # 构建Bulb类用于控制,传入IP参数
11 |
12 | bulb.turn_on() # 开灯
13 | sleep(2)
14 | bulb.turn_off() # 关灯
15 | sleep(2)
16 | bulb.toggle() # 翻转
17 | sleep(2)
18 | bulb.set_rgb(255,0,0) # 设置RGB值
19 | bulb.set_brightness(50) # 调节亮度
20 | sleep(2)
21 | bulb.set_hsv(180,100) # 设置HSV值
22 | sleep(2)
23 |
--------------------------------------------------------------------------------
/library/yeelight/images/mpython.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/yeelight/images/mpython.png
--------------------------------------------------------------------------------
/library/yeelight/images/yeelight.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/yeelight/images/yeelight.png
--------------------------------------------------------------------------------
/library/yeelight/optimize_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This script optimizes a Python source distribution tarball as produced by
3 | # "python3 setup.py sdist" command for MicroPython's native package manager,
4 | # upip. Optimization includes:
5 | # * Removing metadata files not used by upip (this includes setup.py)
6 | # * Recompressing gzip archive with 4K dictionary size so it can be
7 | # installed even on low-heap targets.
8 | #
9 | import sys
10 | import os
11 | import zlib
12 | from subprocess import Popen, PIPE
13 | import glob
14 | import tarfile
15 | import re
16 | import io
17 |
18 |
19 | def gzip_4k(inf, fname):
20 | comp = zlib.compressobj(level=9, wbits=16 + 12)
21 | with open(fname + ".out", "wb") as outf:
22 | while 1:
23 | data = inf.read(1024)
24 | if not data:
25 | break
26 | outf.write(comp.compress(data))
27 | outf.write(comp.flush())
28 | os.rename(fname, fname + ".orig")
29 | os.rename(fname + ".out", fname)
30 |
31 |
32 | def recompress(fname):
33 | with Popen(["gzip", "-d", "-c", fname], stdout=PIPE).stdout as inf:
34 | gzip_4k(inf, fname)
35 |
36 | def find_latest(dir):
37 | res = []
38 | for fname in glob.glob(dir + "/*.gz"):
39 | st = os.stat(fname)
40 | res.append((st.st_mtime, fname))
41 | res.sort()
42 | latest = res[-1][1]
43 | return latest
44 |
45 |
46 | def recompress_latest(dir):
47 | latest = find_latest(dir)
48 | print(latest)
49 | recompress(latest)
50 |
51 |
52 | FILTERS = [
53 | # include, exclude, repeat
54 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
55 | (r".+\.py$", r"[^/]+$"),
56 | (None, r".+\.egg-info/.+"),
57 | ]
58 |
59 |
60 | outbuf = io.BytesIO()
61 |
62 | def filter_tar(name):
63 | fin = tarfile.open(name, "r:gz")
64 | fout = tarfile.open(fileobj=outbuf, mode="w")
65 | for info in fin:
66 | # print(info)
67 | if not "/" in info.name:
68 | continue
69 | fname = info.name.split("/", 1)[1]
70 | include = None
71 |
72 | for inc_re, exc_re in FILTERS:
73 | if include is None and inc_re:
74 | if re.match(inc_re, fname):
75 | include = True
76 |
77 | if include is None and exc_re:
78 | if re.match(exc_re, fname):
79 | include = False
80 |
81 | if include is None:
82 | include = True
83 |
84 | if include:
85 | print("Including:", fname)
86 | else:
87 | print("Excluding:", fname)
88 | continue
89 |
90 | farch = fin.extractfile(info)
91 | fout.addfile(info, farch)
92 | fout.close()
93 | fin.close()
94 |
95 |
96 |
97 | from setuptools import Command
98 |
99 | class OptimizeUpip(Command):
100 |
101 | user_options = []
102 |
103 | def run(self):
104 | latest = find_latest("dist")
105 | filter_tar(latest)
106 | outbuf.seek(0)
107 | gzip_4k(outbuf, latest)
108 |
109 | def initialize_options(self):
110 | pass
111 |
112 | def finalize_options(self):
113 | pass
114 |
115 |
116 | # For testing only
117 | if __name__ == "__main__":
118 | # recompress_latest(sys.argv[1])
119 | filter_tar(sys.argv[1])
120 | outbuf.seek(0)
121 | gzip_4k(outbuf, sys.argv[1])
122 |
--------------------------------------------------------------------------------
/library/yeelight/sdist_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This module overrides distutils (also compatible with setuptools) "sdist"
3 | # command to perform pre- and post-processing as required for MicroPython's
4 | # upip package manager.
5 | #
6 | # Preprocessing steps:
7 | # * Creation of Python resource module (R.py) from each top-level package's
8 | # resources.
9 | # Postprocessing steps:
10 | # * Removing metadata files not used by upip (this includes setup.py)
11 | # * Recompressing gzip archive with 4K dictionary size so it can be
12 | # installed even on low-heap targets.
13 | #
14 | import sys
15 | import os
16 | import zlib
17 | from subprocess import Popen, PIPE
18 | import glob
19 | import tarfile
20 | import re
21 | import io
22 |
23 | from distutils.filelist import FileList
24 | from setuptools.command.sdist import sdist as _sdist
25 |
26 |
27 | def gzip_4k(inf, fname):
28 | comp = zlib.compressobj(level=9, wbits=16 + 12)
29 | with open(fname + ".out", "wb") as outf:
30 | while 1:
31 | data = inf.read(1024)
32 | if not data:
33 | break
34 | outf.write(comp.compress(data))
35 | outf.write(comp.flush())
36 | os.rename(fname, fname + ".orig")
37 | os.rename(fname + ".out", fname)
38 |
39 |
40 | FILTERS = [
41 | # include, exclude, repeat
42 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
43 | (r".+\.py$", r"[^/]+$"),
44 | (None, r".+\.egg-info/.+"),
45 | ]
46 |
47 |
48 | outbuf = io.BytesIO()
49 |
50 | def filter_tar(name):
51 | fin = tarfile.open(name, "r:gz")
52 | fout = tarfile.open(fileobj=outbuf, mode="w")
53 | for info in fin:
54 | # print(info)
55 | if not "/" in info.name:
56 | continue
57 | fname = info.name.split("/", 1)[1]
58 | include = None
59 |
60 | for inc_re, exc_re in FILTERS:
61 | if include is None and inc_re:
62 | if re.match(inc_re, fname):
63 | include = True
64 |
65 | if include is None and exc_re:
66 | if re.match(exc_re, fname):
67 | include = False
68 |
69 | if include is None:
70 | include = True
71 |
72 | if include:
73 | print("including:", fname)
74 | else:
75 | print("excluding:", fname)
76 | continue
77 |
78 | farch = fin.extractfile(info)
79 | fout.addfile(info, farch)
80 | fout.close()
81 | fin.close()
82 |
83 |
84 | def make_resource_module(manifest_files):
85 | resources = []
86 | # Any non-python file included in manifest is resource
87 | for fname in manifest_files:
88 | ext = fname.rsplit(".", 1)[1]
89 | if ext != "py":
90 | resources.append(fname)
91 |
92 | if resources:
93 | print("creating resource module R.py")
94 | resources.sort()
95 | last_pkg = None
96 | r_file = None
97 | for fname in resources:
98 | try:
99 | pkg, res_name = fname.split("/", 1)
100 | except ValueError:
101 | print("not treating %s as a resource" % fname)
102 | continue
103 | if last_pkg != pkg:
104 | last_pkg = pkg
105 | if r_file:
106 | r_file.write("}\n")
107 | r_file.close()
108 | r_file = open(pkg + "/R.py", "w")
109 | r_file.write("R = {\n")
110 |
111 | with open(fname, "rb") as f:
112 | r_file.write("%r: %r,\n" % (res_name, f.read()))
113 |
114 | if r_file:
115 | r_file.write("}\n")
116 | r_file.close()
117 |
118 |
119 | class sdist(_sdist):
120 |
121 | def run(self):
122 | self.filelist = FileList()
123 | self.get_file_list()
124 | make_resource_module(self.filelist.files)
125 |
126 | r = super().run()
127 |
128 | assert len(self.archive_files) == 1
129 | print("filtering files and recompressing with 4K dictionary")
130 | filter_tar(self.archive_files[0])
131 | outbuf.seek(0)
132 | gzip_4k(outbuf, self.archive_files[0])
133 |
134 | return r
135 |
136 |
137 | # For testing only
138 | if __name__ == "__main__":
139 | filter_tar(sys.argv[1])
140 | outbuf.seek(0)
141 | gzip_4k(outbuf, sys.argv[1])
142 |
--------------------------------------------------------------------------------
/library/yeelight/setup.cfg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/labplus-cn/awesome-mpython/b4539ad58dc465be065bfca6fe27211b3f5ed05d/library/yeelight/setup.cfg
--------------------------------------------------------------------------------
/library/yeelight/setup.py:
--------------------------------------------------------------------------------
1 | # import sys
2 | # sys.path.pop(0)
3 | # sys.path.append("..")
4 | from setuptools import setup
5 | import sdist_upip
6 | from os import path
7 |
8 | # read the contents of your README file
9 | from os import path
10 | this_directory = path.abspath(path.dirname(__file__))
11 | with open(path.join(this_directory, 'README.md'), encoding='utf-8') as f:
12 | long_description = f.read()
13 |
14 | VERSION= '0.0.1'
15 |
16 | setup(name='mPython-yeelight',
17 | version=VERSION,
18 | description='Yeelight LAN Control for mPython/micropython',
19 | long_description=long_description,
20 | long_description_content_type="text/markdown",
21 | url='https://github.com/labplus-cn/mPython_yeelight',
22 | author='tangliufeng@LabPlus',
23 | author_email='137513285@qq.com',
24 | maintainer='LabPlus Developers',
25 | license='MIT',
26 | cmdclass={'sdist': sdist_upip.sdist},
27 | py_modules=['yeelight'],
28 | # packages=['email'],
29 | # install_requires=['']
30 | )
31 |
32 |
--------------------------------------------------------------------------------
/library/yeelight/yeelight.py:
--------------------------------------------------------------------------------
1 | import socket
2 | import json
3 |
4 | def discover_bulbs(timeout=2):
5 | """
6 | 发现所有局域网内的Yeelight灯泡.
7 |
8 | :param int timeout: 等待回复需要多少秒。发现将总是要花这么长的时间,
9 | 因为它不知道当所有的灯泡都响应完毕时。
10 | :returns: 字典列表,包含网络中每个灯泡的IP,端口和功能。
11 | """
12 | msg = 'M-SEARCH * HTTP/1.1\r\n' \
13 | 'ST:wifi_bulb\r\n' \
14 | 'MAN:"ssdp:discover"\r\n'
15 |
16 | # Set up UDP socket
17 | s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
18 | s.settimeout(timeout)
19 | s.sendto(msg.encode(), ('239.255.255.250', 1982))
20 | read_buf = 1024
21 | bulbs = []
22 | bulb_ips = set()
23 | while True:
24 | try:
25 | data, addr = s.recvfrom(read_buf)
26 | except OSError:
27 | break
28 |
29 | capabilities = dict([x.strip("\r").split(": ")
30 | for x in data.decode().split("\n") if ":" in x])
31 | parsed_url = capabilities["Location"].split("//")[1]
32 |
33 | bulb_ip = tuple(parsed_url.split(":"))
34 | if bulb_ip in bulb_ips:
35 | continue
36 |
37 | capabilities = {key: value for key,
38 | value in capabilities.items() if key.islower()}
39 | bulbs.append(
40 | {"ip": bulb_ip[0], "port": bulb_ip[1], "capabilities": capabilities})
41 | bulb_ips.add(bulb_ip)
42 |
43 | return bulbs
44 |
45 |
46 | class BulbException(Exception):
47 | """
48 | 一般的 yeelight 异常类
49 |
50 | 当灯泡通知错误时会引发此异常,例如,当尝试向灯泡发出不支持的命令时。
51 | """
52 | pass
53 |
54 |
55 | class Bulb(object):
56 | """
57 | YeeLight的控制类.
58 |
59 | :param str ip: 灯泡的IP.
60 | :param int port: 连接灯泡的端口号,默认55443.
61 | :param str effect: 效果类型."smooth" or "sudden".
62 | :param int duration: 效果的持续时间,以毫秒为单位.最小值为30.突然效果会忽略此值.
63 | :param bool auto_on: 是否 :py:meth:`ensure_on()
64 | ` 在每次操作之前调用以自动打开灯泡,如果它已关闭。这会在每条消息之前更新灯泡的属性,
65 | 每个命令会花费一个额外的消息。 如果您担心速率限制,请将其关闭并自行检查。:py:meth:`get_properties()`
66 | 或运行 :py:meth:`ensure_on() `
67 | """
68 |
69 | def __init__(self, ip, port=55443, effect="smooth",
70 | duration=300, auto_on=False):
71 |
72 | self._ip = ip
73 | self._port = port
74 | self._timeout = 5
75 |
76 | self.effect = effect
77 | self.duration = duration
78 | self.auto_on = auto_on
79 |
80 | self.__cmd_id = 0 # The last command id we used.
81 | self._last_properties = {} # The last set of properties we've seen.
82 | self._music_mode = False # Whether we're currently in music mode.
83 | self.__socket = None # The socket we use to communicate.
84 |
85 | @property
86 | def _cmd_id(self):
87 | '''
88 | Get next command id in sequence
89 |
90 | :return: command id
91 | '''
92 | self.__cmd_id += 1
93 | return self.__cmd_id - 1
94 |
95 | @property
96 | def _socket(self):
97 | '''
98 | Get, optionally create, the communication socket
99 |
100 | :return: the communication socket
101 | '''
102 | if self.__socket is None:
103 | self.__socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
104 | self.__socket.settimeout(self._timeout)
105 | self.__socket.connect((self._ip, self._port))
106 |
107 | return self.__socket
108 |
109 | def ensure_on(self):
110 | """Turn the bulb on if it is off."""
111 | if self._music_mode is True or self.auto_on is False:
112 | return
113 |
114 | self.get_properties()
115 |
116 | if self._last_properties["power"] != "on":
117 | self.turn_on()
118 |
119 | @property
120 | def music_mode(self):
121 | """
122 | Return whether the music mode is active.
123 |
124 | :rtype: bool
125 | :return: True if music mode is on, False otherwise.
126 | """
127 | return self._music_mode
128 |
129 | @property
130 | def last_properties(self):
131 | """
132 | The last properties we've seen the bulb have.
133 |
134 | This might potentially be out of date, as there's no background listener
135 | for the bulb's notifications. To update it, call
136 | :py:meth:`get_properties `.
137 | """
138 | return self._last_properties
139 |
140 | def get_properties(self):
141 | """
142 | Retrieve and return the properties of the bulb.
143 |
144 | This method also updates ``last_properties`` when it is called.
145 |
146 | :returns: A dictionary of param: value items.
147 | :rtype: dict
148 | """
149 | # When we are in music mode, the bulb does not respond to queries
150 | # therefore we need to keep the state up-to-date ourselves
151 | if self._music_mode:
152 | return self._last_properties
153 |
154 | requested_properties = [
155 | "power", "bright", "ct", "rgb", "hue", "sat",
156 | "color_mode", "flowing", "delayoff", "flow_params",
157 | "music_on", "name"
158 | ]
159 | response = self.send_command("get_prop", requested_properties)
160 | properties = response["result"]
161 | properties = [x if x else None for x in properties]
162 |
163 | self._last_properties = dict(zip(requested_properties, properties))
164 | return self._last_properties
165 |
166 | def ensure_on(self):
167 | """Turn the bulb on if it is off."""
168 | if self._music_mode is True or self.auto_on is False:
169 | return
170 |
171 | self.get_properties()
172 |
173 | if self._last_properties["power"] != "on":
174 | self.turn_on()
175 |
176 | @property
177 | def bulb_type(self):
178 | """
179 | 灯泡类型
180 |
181 | 返回灯泡类型:White or Color.当尝试在属性已知之前访问时,灯泡类型是未知的。
182 |
183 | :return: 灯泡类型.
184 | """
185 | if not self._last_properties:
186 | return "BulbType.Unknown"
187 | if not all(name in self.last_properties for name in ['ct', 'rgb', 'hue', 'sat']):
188 | return "BulbType.White"
189 | else:
190 | return "BulbType.Color"
191 |
192 | def send_command(self, method, params=None):
193 | """
194 | 请求信息并返回响应
195 |
196 | :param str method: control method id
197 | :param list params: list of params for the specified method
198 | :return: the command response
199 | """
200 |
201 | command = {'id': self._cmd_id, 'method': method, 'params': params}
202 | # print(command)
203 | try:
204 | self._socket.send((json.dumps(command) + '\r\n').encode('utf8'))
205 | except Exception as e:
206 | self.__socket.close()
207 | self.__socket = None
208 | raise BulbException(
209 | 'A socket error occurred when sending the command.')
210 |
211 | if self._music_mode:
212 | # We're in music mode, nothing else will happen.
213 | return {"result": ["ok"]}
214 |
215 | # The bulb will send us updates on its state in addition to responses,
216 | # so we want to make sure that we read until we see an actual response.
217 | response = None
218 | while response is None:
219 | try:
220 | data = self._socket.recv(2 * 1024)
221 | except:
222 | self.__socket.close()
223 | self.__socket = None
224 | response = {'error': 'Bulb closed the connection.'}
225 | break
226 |
227 | for line in data.split(b'\r\n'):
228 | if not line:
229 | continue
230 |
231 | try:
232 | line = json.loads(line.decode('utf8'))
233 | except ValueError:
234 | response = {'result': ['invalid command']}
235 |
236 | if line.get('method') != 'props':
237 | response = line
238 |
239 | else:
240 | self._last_properties.update(line["params"])
241 |
242 | if "error" in response:
243 | raise BulbException(response["error"])
244 |
245 | return response
246 |
247 | @property
248 | def name(self):
249 | '''
250 | 设置或返回设备名字
251 |
252 | :return: 返回设备名字
253 | '''
254 | return self.send_command('get_prop', ['name'])['result']
255 |
256 | @name.setter
257 | def name(self, name):
258 | '''
259 | 设置设备名字
260 | :param name: new name
261 | '''
262 | self.send_command('set_name', [name])
263 |
264 | @property
265 | def is_on(self):
266 | '''
267 | 返回灯泡是否打开
268 |
269 | :return:打开则是'on',关闭侧'off'。
270 | '''
271 | return self.send_command('get_prop', ['power'])['result'][0] == 'on'
272 |
273 | def turn_on(self):
274 | '''
275 | 打开灯泡
276 | '''
277 | self.send_command('set_power', ['on', self.effect, self.duration])
278 |
279 | def turn_off(self):
280 | '''
281 | 关闭灯泡
282 | '''
283 | self.send_command('set_power', ['off', self.effect, self.duration])
284 |
285 | def toggle(self):
286 | """反转灯泡状态."""
287 | self.send_command('toggle', [])
288 |
289 | def set_rgb(self, red, green, blue):
290 | '''
291 | 设置灯泡的RGB值
292 |
293 | :param int red: 红色范围 (0-255)
294 | :param int green: 绿色范围 (0-255)
295 | :param int blue: 蓝色范围 (0-255)
296 | '''
297 |
298 | self.ensure_on()
299 |
300 | red = max(0, min(255, red))
301 | green = max(0, min(255, green))
302 | blue = max(0, min(255, blue))
303 |
304 | self.send_command(
305 | 'set_rgb', [red * 65536 + green * 256 + blue, self.effect, self.duration])
306 |
307 |
308 | def set_hsv(self, hue, saturation):
309 | """
310 | Set the bulb's HSV value.
311 |
312 | :param int hue: The hue to set (0-359).
313 | :param int saturation: The saturation to set (0-100).
314 |
315 | """
316 | self.ensure_on()
317 |
318 | # We fake this using flow so we can add the `value` parameter.
319 | hue = max(0, min(359, hue))
320 | saturation = max(0, min(100, saturation))
321 |
322 | self.send_command('set_hsv', [hue, saturation,self.effect, self.duration])
323 |
324 |
325 | def set_color_temp(self, degrees):
326 | """
327 | 设置灯泡色温
328 |
329 | :param int degrees: 色温范围(1700-6500).
330 | """
331 | self.ensure_on()
332 |
333 | degrees = max(1700, min(6500, degrees))
334 | self.send_command('set_ct_abx', [degrees, self.effect, self.duration])
335 |
336 | def set_adjust(self, action, prop):
337 | """
338 | 该方法用于改变智能LED的亮度、CT或颜色,在不知道当前值的情况下.
339 |
340 | :param str action: 调整方向,可以的值是,'increase' : 增加指定属性;100'decrease': 减小指定属性;'circle': 增加指定的属性,当它达到最大值后,回到最小值.
341 | :param str prop: 属性调制. 可以是 "bright" 亮度调整, "ct" 色温调整, "color"
342 | 颜色调整.
343 | """
344 |
345 | self.send_command('set_adjust', [action, prop])
346 |
347 | def set_brightness(self, brightness):
348 | """
349 | 设置灯泡亮度
350 |
351 | :param int brightness: 亮度范围 (1-100).
352 | """
353 | self.ensure_on()
354 |
355 | brightness = int(max(1, min(100, brightness)))
356 | self.send_command(
357 | 'set_bright', [brightness, self.effect, self.duration])
358 |
359 | def start_flow(self, flow):
360 | '''
361 | Start a flow
362 |
363 | :param yeelight.Flow flow: the Flow instance to start
364 | '''
365 | if not isinstance(flow, Flow):
366 | raise ValueError('Argument is not a Flow instance')
367 | self.ensure_on()
368 | self.send_command('start_cf', [
369 | flow.count * len(flow.transitions), flow.action, flow.expression])
370 |
371 |
372 | def cron_add(self, event_type, value):
373 | """
374 | Add an event to cron.
375 | """
376 | self.send_command('cron_add', [event_type.value, value])
377 |
378 | def cron_get(self, event_type):
379 | """
380 | Retrieve an event from cron.
381 | """
382 | self.send_command('cron_get', [event_type])
383 |
384 | def cron_del(self, event_type):
385 | """
386 | Remove an event from cron.
387 | """
388 | self.send_command('cron_del', [event_type])
389 |
--------------------------------------------------------------------------------
/mkdocs.yml:
--------------------------------------------------------------------------------
1 | site_name: 'Awesome mPython'
2 | site_url: 'https://labplus-cn.github.io/awesome-mpython/'
3 | site_description: 'A curated list of mpython libraries, frameworks, software and resources.'
4 | site_author: 'tangliufeng'
5 | repo_name: 'labplus-cn/awesome-micropython'
6 | repo_url: 'https://github.com/labplus-cn/awesome-mpython'
7 | edit_uri: ''
8 |
9 |
10 | theme:
11 | name: 'material'
12 | language: 'en'
13 | # logo: 'img/logo.svg'
14 | favicon: 'images/favicon.ico'
15 | palette:
16 | primary: 'teal'
17 | accent: 'teal'
18 | nav:
19 | - 'MicroPython精选': 'index.md'
20 |
21 |
22 | plugins:
23 | - search
24 | - minify
25 |
--------------------------------------------------------------------------------
/optimize_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This script optimizes a Python source distribution tarball as produced by
3 | # "python3 setup.py sdist" command for MicroPython's native package manager,
4 | # upip. Optimization includes:
5 | # * Removing metadata files not used by upip (this includes setup.py)
6 | # * Recompressing gzip archive with 4K dictionary size so it can be
7 | # installed even on low-heap targets.
8 | #
9 | import sys
10 | import os
11 | import zlib
12 | from subprocess import Popen, PIPE
13 | import glob
14 | import tarfile
15 | import re
16 | import io
17 |
18 |
19 | def gzip_4k(inf, fname):
20 | comp = zlib.compressobj(level=9, wbits=16 + 12)
21 | with open(fname + ".out", "wb") as outf:
22 | while 1:
23 | data = inf.read(1024)
24 | if not data:
25 | break
26 | outf.write(comp.compress(data))
27 | outf.write(comp.flush())
28 | os.rename(fname, fname + ".orig")
29 | os.rename(fname + ".out", fname)
30 |
31 |
32 | def recompress(fname):
33 | with Popen(["gzip", "-d", "-c", fname], stdout=PIPE).stdout as inf:
34 | gzip_4k(inf, fname)
35 |
36 | def find_latest(dir):
37 | res = []
38 | for fname in glob.glob(dir + "/*.gz"):
39 | st = os.stat(fname)
40 | res.append((st.st_mtime, fname))
41 | res.sort()
42 | latest = res[-1][1]
43 | return latest
44 |
45 |
46 | def recompress_latest(dir):
47 | latest = find_latest(dir)
48 | print(latest)
49 | recompress(latest)
50 |
51 |
52 | FILTERS = [
53 | # include, exclude, repeat
54 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
55 | (r".+\.py$", r"[^/]+$"),
56 | (None, r".+\.egg-info/.+"),
57 | ]
58 |
59 |
60 | outbuf = io.BytesIO()
61 |
62 | def filter_tar(name):
63 | fin = tarfile.open(name, "r:gz")
64 | fout = tarfile.open(fileobj=outbuf, mode="w")
65 | for info in fin:
66 | # print(info)
67 | if not "/" in info.name:
68 | continue
69 | fname = info.name.split("/", 1)[1]
70 | include = None
71 |
72 | for inc_re, exc_re in FILTERS:
73 | if include is None and inc_re:
74 | if re.match(inc_re, fname):
75 | include = True
76 |
77 | if include is None and exc_re:
78 | if re.match(exc_re, fname):
79 | include = False
80 |
81 | if include is None:
82 | include = True
83 |
84 | if include:
85 | print("Including:", fname)
86 | else:
87 | print("Excluding:", fname)
88 | continue
89 |
90 | farch = fin.extractfile(info)
91 | fout.addfile(info, farch)
92 | fout.close()
93 | fin.close()
94 |
95 |
96 |
97 | from setuptools import Command
98 |
99 | class OptimizeUpip(Command):
100 |
101 | user_options = []
102 |
103 | def run(self):
104 | latest = find_latest("dist")
105 | filter_tar(latest)
106 | outbuf.seek(0)
107 | gzip_4k(outbuf, latest)
108 |
109 | def initialize_options(self):
110 | pass
111 |
112 | def finalize_options(self):
113 | pass
114 |
115 |
116 | # For testing only
117 | if __name__ == "__main__":
118 | # recompress_latest(sys.argv[1])
119 | filter_tar(sys.argv[1])
120 | outbuf.seek(0)
121 | gzip_4k(outbuf, sys.argv[1])
122 |
--------------------------------------------------------------------------------
/sdist_upip.py:
--------------------------------------------------------------------------------
1 | #
2 | # This module overrides distutils (also compatible with setuptools) "sdist"
3 | # command to perform pre- and post-processing as required for MicroPython's
4 | # upip package manager.
5 | #
6 | # Preprocessing steps:
7 | # * Creation of Python resource module (R.py) from each top-level package's
8 | # resources.
9 | # Postprocessing steps:
10 | # * Removing metadata files not used by upip (this includes setup.py)
11 | # * Recompressing gzip archive with 4K dictionary size so it can be
12 | # installed even on low-heap targets.
13 | #
14 | import sys
15 | import os
16 | import zlib
17 | from subprocess import Popen, PIPE
18 | import glob
19 | import tarfile
20 | import re
21 | import io
22 |
23 | from distutils.filelist import FileList
24 | from setuptools.command.sdist import sdist as _sdist
25 |
26 |
27 | def gzip_4k(inf, fname):
28 | comp = zlib.compressobj(level=9, wbits=16 + 12)
29 | with open(fname + ".out", "wb") as outf:
30 | while 1:
31 | data = inf.read(1024)
32 | if not data:
33 | break
34 | outf.write(comp.compress(data))
35 | outf.write(comp.flush())
36 | os.rename(fname, fname + ".orig")
37 | os.rename(fname + ".out", fname)
38 |
39 |
40 | FILTERS = [
41 | # include, exclude, repeat
42 | (r".+\.egg-info/(PKG-INFO|requires\.txt)", r"setup.py$"),
43 | (r".+\.py$", r"[^/]+$"),
44 | (None, r".+\.egg-info/.+"),
45 | ]
46 |
47 |
48 | outbuf = io.BytesIO()
49 |
50 | def filter_tar(name):
51 | fin = tarfile.open(name, "r:gz")
52 | fout = tarfile.open(fileobj=outbuf, mode="w")
53 | for info in fin:
54 | # print(info)
55 | if not "/" in info.name:
56 | continue
57 | fname = info.name.split("/", 1)[1]
58 | include = None
59 |
60 | for inc_re, exc_re in FILTERS:
61 | if include is None and inc_re:
62 | if re.match(inc_re, fname):
63 | include = True
64 |
65 | if include is None and exc_re:
66 | if re.match(exc_re, fname):
67 | include = False
68 |
69 | if include is None:
70 | include = True
71 |
72 | if include:
73 | print("including:", fname)
74 | else:
75 | print("excluding:", fname)
76 | continue
77 |
78 | farch = fin.extractfile(info)
79 | fout.addfile(info, farch)
80 | fout.close()
81 | fin.close()
82 |
83 |
84 | def make_resource_module(manifest_files):
85 | resources = []
86 | # Any non-python file included in manifest is resource
87 | for fname in manifest_files:
88 | ext = fname.rsplit(".", 1)[1]
89 | if ext != "py":
90 | resources.append(fname)
91 |
92 | if resources:
93 | print("creating resource module R.py")
94 | resources.sort()
95 | last_pkg = None
96 | r_file = None
97 | for fname in resources:
98 | try:
99 | pkg, res_name = fname.split("/", 1)
100 | except ValueError:
101 | print("not treating %s as a resource" % fname)
102 | continue
103 | if last_pkg != pkg:
104 | last_pkg = pkg
105 | if r_file:
106 | r_file.write("}\n")
107 | r_file.close()
108 | r_file = open(pkg + "/R.py", "w")
109 | r_file.write("R = {\n")
110 |
111 | with open(fname, "rb") as f:
112 | r_file.write("%r: %r,\n" % (res_name, f.read()))
113 |
114 | if r_file:
115 | r_file.write("}\n")
116 | r_file.close()
117 |
118 |
119 | class sdist(_sdist):
120 |
121 | def run(self):
122 | self.filelist = FileList()
123 | self.get_file_list()
124 | make_resource_module(self.filelist.files)
125 |
126 | r = super().run()
127 |
128 | assert len(self.archive_files) == 1
129 | print("filtering files and recompressing with 4K dictionary")
130 | filter_tar(self.archive_files[0])
131 | outbuf.seek(0)
132 | gzip_4k(outbuf, self.archive_files[0])
133 |
134 | return r
135 |
136 |
137 | # For testing only
138 | if __name__ == "__main__":
139 | filter_tar(sys.argv[1])
140 | outbuf.seek(0)
141 | gzip_4k(outbuf, sys.argv[1])
142 |
--------------------------------------------------------------------------------