First commit

This commit is contained in:
Alexandre 2025-03-22 00:49:46 +01:00
commit e52bf4d0af
757 changed files with 1054494 additions and 0 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

View File

@ -0,0 +1,41 @@
from machine import Pin, PWM
import time
pin_led = PWM(Pin(16, mode=Pin.OUT))
pin_bpblue = Pin(20, mode=Pin.IN)
pin_bpred = Pin(21, mode=Pin.IN)
led=0
gyro = 0
while True:
etat_BPblue = pin_bpblue.value()
etat_BPred = pin_bpred.value()
if (etat_BPred == False) and (etat_BPblue == False):
print('Nous avons besoin de votre aide')
elif (etat_BPblue == False):
print('Bonjour habitants de la planète Algoréa')
while gyro <= 10:
pin_led.value(True)
time.sleep(0.1)
pin_led.value(False)
time.sleep(0.1)
gyro = gyro +1
elif (etat_BPred == False):
print('Nous venons de la planète Terre')
if led == 0:
pin_led.value(True)
led = 1
elif led == 1:
pin_led.value(False)
led = 0
else:
print('Released')
time.sleep(0.5)
gyro = 0
'''
pin_led.value(True)
time.sleep(1)
pin_led.value(False)
time.sleep(1)
'''

View File

@ -0,0 +1,35 @@
# Import all libs
from machine import PWM, Pin, ADC
import time
# Value definitions
pwm_const = 65535
pwm_percentage = 0.80
# Make calculations on the cont to use it later
cycle = int(pwm_const*pwm_percentage)
# Define pins to use
led_pwm = PWM(Pin(16, mode=Pin.OUT))
adc_pin = Pin(26, mode=Pin.IN)
pin_bpblue = Pin(20, mode=Pin.IN)
pin_bpred = Pin(21, mode=Pin.IN)
# Define parameters
led_pwm.freq(50)
adc = ADC(adc_pin)
# Main loop
led_pwm.duty_u16(cycle)
while True :
etat_BPblue = pin_bpblue.value()
etat_BPred = pin_bpred.value()
N = adc.read_u16();
led_pwm.duty_u16(N)
if (etat_BPred == False) and (etat_BPblue == False):
time.sleep(5)
print(N)
time.sleep(0.01)
'''
pin_led.value(True)
'''

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,218 @@
# Sommaire :
- Cahier de charges
- Le matériel utilisé
- Les parties importantes du code
- Le code
- Le schéma de lalgorithme
- Captures d'écrans (page bluetooth et comment ça fonctionne + page HTML)
## Le Cahier de Charges
*Problématique:* Comment récupérer les mesures du monde réel grâce a des capteurs pour les rendre accessibles ?
*Objectif du projet:* Nous voulions créer une station météo portative sur laquelle on peut connaitre différentes mesures de notre environnement (Taux de CO2, Température, Humidité et Pression Atmosphérique). Pour voir ces mesures, on peut utiliser l'écran LCD intégré, une application reliée en Bluetooth, ou une page internet, par Wi-Fi.
*Périmètre du projet:* Nous nous concentrons sur des personnes désignées.
*Description fonctionnelle de besoin:* L'application doit être en capacité de renvoyer sur l'écran, les valeurs mesurées par les capteurs tout en renouvelant ces données toutes les 10 secondes pour des valeurs presque en temps réel.
*Contraintes:* être capable d'avoir des valeurs précises et cohérentes.
*Délais*: le projet a commencé le 18/12/2024 et on aura terminer vers le 24/01/2025 avec quelques jours de délais pour finaliser le compte rendu.
## Le matériel utilisé
Pour réaliser ce projet, nous avions eu besoin de quelques éléments matériels :
- Une carte Raspberry Pi PICO: elle sert a contrôler les différents capteurs et l'écran
- Un capteur SGP30 (Gaz)
- Un capteur BME280 (Température, pression atmoshérique et humidité)
- Afficheur LCD I2C Grove
## Le code
````
# Importe tout les modules requis
from machine import Pin, I2C, UART
import uSGP30
import uBME280
from i2c_lcd import lcd
import time
# Défini l'interface du protocole I2C
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 1024)
# Défini l'interface UART utilisée pour le Bluetooth
BT = UART(1, baudrate = 9600, tx = Pin(4), rx = Pin(5))
# Défuini les adresses I2C requis pour les capteurs
BME_addr = 0x76;
SGP30_adrr = 0x58;
# Déclare les paramètres des capteurs
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
# Le BME280 prends comme argument : le mode du capteur, l'adresse i2c du capteur et l'interface du protocole i2c
sgp30 = uSGP30.SGP30(i2c, SGP30_adrr)
# Le SGP30 prends comme argument : l'interface du protocole i2c et l'adresse i2c du capteur
display = lcd(i2c)
# Crée les variables contenants les valeurs extérieures
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
# Les valeurs ci dessus doivent être converties en texte car l'écran requiers des valeurs car sinon le programe renvoie une "TypeError: object with buffer protocol required"
# De plus, les valeurs doivent êtres divisés par 100 ou par 1000 car elles ne sont pas dans la bonne unitée (capteur en pascal, valeur attendue en kPascal)
t_CO2, t_COV = sgp30.measure_iaq()
co2 = str(t_CO2)
# Crée la fonction qui permet de récupérer les valeurs
def Update_Valeurs():
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
t_CO2, t_COV = sgp30.measure_iaq()
co2 = str(t_CO2)
# Crée la fonction qui permet d'afficher le "premier écran"
def First_Screen():
# Affiche le premier "écran" (Température + Humidité)
display.home()
display.write("Temp = ")
display.write(t)
display.write(" °C")
display.setCursor(0,1)
display.write("THum = ")
display.write(h)
display.write(" %")
# Crée la fonction qui permet d'afficher le "deuxième écran"
def Second_Screen():
# Affiche le deuxième "écran" (Pression + CO2)
display.clear()
display.home()
display.write("P = ")
display.write(p)
display.write(" Pa")
display.setCursor(0,1)
display.write("TCO2 = ")
display.write(co2)
display.write(" ppm")
# Crée la fonction qui permet d'afficher les valeurs
def Update_Screen():
# Affiche le premier "écran"
First_Screen()
time.sleep(5)
Second_Screen()
time.sleep(5)
display.clear()
# Crée la fonction qui permet d'envoyer les valeurs en bluetooth
def Send_Datas(a, b, c, d):
BT.write(a)
BT.write(b)
BT.write(c)
BT.write(d)
# Lance le programme indéfiniment
while True:
Update_Valeurs()
Send_Datas(t, h, p, co2)
Update_Screen()
````
## Les parties importantes du code
### La fonction Update_Values() qui permet de récupérer les valeurs des différents capteurs
`def Update_Values():` Crée la fonction avec le mot-clé "def"
`t = str(bme280.read_temperature()/100)` Récupère la température depuis le BME280, la transforme en "str" pour que l'écran puisse l'afficher et divise par 100 pour adapter à la bonne unité
`p = str(bme280.read_pressure()/1000)` Récupère la pression atmosphérique depuis le BME280, la transforme en "str" pour que l'écran puisse l'afficher et divise par 1000 pour adapter à la bonne unité
`h = str(bme280.read_humidity()/1000)` Récupère l'humidité depuis le BME280, la transforme en "str" pour que l'écran puisse l'afficher et divise par 1000 pour adapter à la bonne unité
`t_CO2, t_COV = sgp30.measure_iaq()` Récupère le taux de CO2 depuis le SGP30
`co2 = str(t_CO2)` Converti le taux de CO2 en "str" pour pouvoir l'afficher sur l'écran
## Schéma de lalgorithme
[[Schéma de l'algorithme.canvas|Schéma de l'algorithme]]
![[Algorigramme.png]]
## Captures d'écran
Capture d'écran de la page Web de la station, avec des éléments de template
![[capture station.PNG]]

View File

@ -0,0 +1,135 @@
from machine import I2C
import time
_I2CADDR = const(0x3E)
# commands
_LCD_CLEARDISPLAY = const(0x01)
_LCD_RETURNHOME = const(0x02)
_LCD_ENTRYMODESET = const(0x04)
_LCD_DISPLAYCONTROL = const(0x08)
_LCD_CURSORSHIFT = const(0x10)
_LCD_FUNCTIONSET = const(0x20)
_LCD_SETCGRAMADDR = const(0x40)
_LCD_SETDDRAMADDR = const(0x80)
# flags for display entry mode
_LCD_ENTRYRIGHT = const(0x00)
_LCD_ENTRYLEFT = const(0x02)
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
# flags for display on/off control
_LCD_DISPLAYON = const(0x04)
_LCD_DISPLAYOFF = const(0x00)
_LCD_CURSORON = const(0x02)
_LCD_CURSOROFF = const(0x00)
_LCD_BLINKON = const(0x01)
_LCD_BLINKOFF = const(0x00)
# flags for display/cursor shift
_LCD_DISPLAYMOVE = const(0x08)
_LCD_CURSORMOVE = const(0x00)
_LCD_MOVERIGHT = const(0x04)
_LCD_MOVELEFT = const(0x00)
# flags for function set
_LCD_8BITMODE = const(0x10)
_LCD_4BITMODE = const(0x00)
_LCD_2LINE = const(0x08)
_LCD_1LINE = const(0x00)
_LCD_5x10DOTS = const(0x04)
_LCD_5x8DOTS = const(0x00)
class lcd:
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
self.i2c = i2c
self.i2c.scan()
self.address = address
self.disp_func = _LCD_DISPLAYON
if not oneline:
self.disp_func |= _LCD_2LINE
elif charsize != 0:
# for 1-line displays you can choose another dotsize
self.disp_func |= _LCD_5x10DOTS
# wait for display init after power-on
time.sleep_ms(50) # 50ms
# send function set
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
# turn on the display
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
self.display(True)
# clear it
self.clear()
# set default text direction (left-to-right)
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
def cmd(self, command):
assert command >= 0 and command < 256
command = bytearray([command])
self.i2c.writeto_mem(self.address, 0x80, command)
def write_char(self, c):
assert c >= 0 and c < 256
c = bytearray([c])
self.i2c.writeto_mem(self.address, 0x40, c)
def write(self, text):
for char in text:
self.write_char(ord(char))
def cursor(self, state):
if state:
self.disp_ctrl |= _LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def setCursor(self, col, row):
col = (col | 0x80) if row == 0 else (col | 0xc0)
self.cmd(col)
def autoscroll(self, state):
if state:
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def blink(self, state):
if state:
self.disp_ctrl |= _LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def display(self, state):
if state:
self.disp_ctrl |= _LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def clear(self):
self.cmd(_LCD_CLEARDISPLAY)
time.sleep_ms(2) # 2ms
def home(self):
self.cmd(_LCD_RETURNHOME)
time.sleep_ms(2) # 2m

View File

@ -0,0 +1,284 @@
from machine import I2C
import time
# BME280 default address.
BME280_I2CADDR = 0x76
# Operating Modes
BME280_OSAMPLE_1 = 1
BME280_OSAMPLE_2 = 2
BME280_OSAMPLE_4 = 3
BME280_OSAMPLE_8 = 4
BME280_OSAMPLE_16 = 5
# BME280 Registers
BME280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
BME280_REGISTER_DIG_T2 = 0x8A
BME280_REGISTER_DIG_T3 = 0x8C
BME280_REGISTER_DIG_P1 = 0x8E
BME280_REGISTER_DIG_P2 = 0x90
BME280_REGISTER_DIG_P3 = 0x92
BME280_REGISTER_DIG_P4 = 0x94
BME280_REGISTER_DIG_P5 = 0x96
BME280_REGISTER_DIG_P6 = 0x98
BME280_REGISTER_DIG_P7 = 0x9A
BME280_REGISTER_DIG_P8 = 0x9C
BME280_REGISTER_DIG_P9 = 0x9E
BME280_REGISTER_DIG_H1 = 0xA1
BME280_REGISTER_DIG_H2 = 0xE1
BME280_REGISTER_DIG_H3 = 0xE3
BME280_REGISTER_DIG_H4 = 0xE4
BME280_REGISTER_DIG_H5 = 0xE5
BME280_REGISTER_DIG_H6 = 0xE6
BME280_REGISTER_DIG_H7 = 0xE7
BME280_REGISTER_CHIPID = 0xD0
BME280_REGISTER_VERSION = 0xD1
BME280_REGISTER_SOFTRESET = 0xE0
BME280_REGISTER_CONTROL_HUM = 0xF2
BME280_REGISTER_CONTROL = 0xF4
BME280_REGISTER_CONFIG = 0xF5
BME280_REGISTER_PRESSURE_DATA = 0xF7
BME280_REGISTER_TEMP_DATA = 0xFA
BME280_REGISTER_HUMIDITY_DATA = 0xFD
class Device:
"""Class for communicating with an I2C device.
Allows reading and writing 8-bit, 16-bit, and byte array values to
registers on the device."""
def __init__(self, address, i2c):
"""Create an instance of the I2C device at the specified address using
the specified I2C interface object."""
self._address = address
self._i2c = i2c
def writeRaw8(self, value):
"""Write an 8-bit value on the bus (without register)."""
value = value & 0xFF
self._i2c.writeto(self._address, value)
def write8(self, register, value):
"""Write an 8-bit value to the specified register."""
b=bytearray(1)
b[0]=value & 0xFF
self._i2c.writeto_mem(self._address, register, b)
def write16(self, register, value):
"""Write a 16-bit value to the specified register."""
value = value & 0xFFFF
b=bytearray(2)
b[0]= value & 0xFF
b[1]= (value>>8) & 0xFF
self.i2c.writeto_mem(self._address, register, value)
def readRaw8(self):
"""Read an 8-bit value on the bus (without register)."""
return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF
def readU8(self, register):
"""Read an unsigned byte from the specified register."""
return int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF
def readS8(self, register):
"""Read a signed byte from the specified register."""
result = self.readU8(register)
if result > 127:
result -= 256
return result
def readU16(self, register, little_endian=True):
"""Read an unsigned 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
if not little_endian:
result = ((result << 8) & 0xFF00) + (result >> 8)
return result
def readS16(self, register, little_endian=True):
"""Read a signed 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = self.readU16(register, little_endian)
if result > 32767:
result -= 65536
return result
def readU16LE(self, register):
"""Read an unsigned 16-bit value from the specified register, in little
endian byte order."""
return self.readU16(register, little_endian=True)
def readU16BE(self, register):
"""Read an unsigned 16-bit value from the specified register, in big
endian byte order."""
return self.readU16(register, little_endian=False)
def readS16LE(self, register):
"""Read a signed 16-bit value from the specified register, in little
endian byte order."""
return self.readS16(register, little_endian=True)
def readS16BE(self, register):
"""Read a signed 16-bit value from the specified register, in big
endian byte order."""
return self.readS16(register, little_endian=False)
class BME280:
def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
**kwargs):
# Check that mode is valid.
if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
raise ValueError(
'Unexpected mode value {0}. Set mode to one of '
'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
'BME280_ULTRAHIGHRES'.format(mode))
self._mode = mode
# Create I2C device.
if i2c is None:
raise ValueError('An I2C object is required.')
self._device = Device(address, i2c)
# Load calibration values.
self._load_calibration()
self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
self.t_fine = 0
def _load_calibration(self):
self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)
self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)
self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)
h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
h4 = (h4 << 24) >> 20
self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)
h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
h5 = (h5 << 24) >> 20
self.dig_H5 = h5 | (
self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)
def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
meas = self._mode
self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
meas = self._mode << 5 | self._mode << 2 | 1
self._device.write8(BME280_REGISTER_CONTROL, meas)
sleep_time = 1250 + 2300 * (1 << self._mode)
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
time.sleep_us(sleep_time) # Wait the required time
msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_pressure(self):
"""Reads the raw (uncompensated) pressure level from the sensor."""
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_humidity(self):
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
raw = (msb << 8) | lsb
return raw
def read_temperature(self):
"""Get the compensated temperature in 0.01 of a degree celsius."""
adc = self.read_raw_temp()
var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
var2 = ((
(((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
self.dig_T3) >> 14
self.t_fine = var1 + var2
return (self.t_fine * 5 + 128) >> 8
def read_pressure(self):
"""Gets the compensated pressure in Pascals."""
adc = self.read_raw_pressure()
var1 = self.t_fine - 128000
var2 = var1 * var1 * self.dig_P6
var2 = var2 + ((var1 * self.dig_P5) << 17)
var2 = var2 + (self.dig_P4 << 35)
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
((var1 * self.dig_P2) >> 12))
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
if var1 == 0:
return 0
p = 1048576 - adc
p = (((p << 31) - var2) * 3125) // var1
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self.dig_P8 * p) >> 19
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
def read_humidity(self):
adc = self.read_raw_humidity()
# print 'Raw humidity = {0:d}'.format (adc)
h = self.t_fine - 76800
h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
self.dig_H2 + 8192) >> 14))
h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
h = 0 if h < 0 else h
h = 419430400 if h > 419430400 else h
return h >> 12
@property
def temperature(self):
"Return the temperature in degrees."
t = self.read_temperature()
ti = t // 100
td = t - ti * 100
return "{}.{:02d}C".format(ti, td)
@property
def pressure(self):
"Return the temperature in hPa."
p = self.read_pressure() // 256
pi = p // 100
pd = p - pi * 100
return "{}.{:02d}hPa".format(pi, pd)
@property
def humidity(self):
"Return the humidity in percent."
h = self.read_humidity()
hi = h // 1024
hd = h * 100 // 1024 - hi * 100
return "{}.{:02d}%".format(hi, hd)

View File

@ -0,0 +1,300 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 ladyada for Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_sgp30`
====================================================
I2C driver for SGP30 Sensirion VoC sensor
* Author(s): ladyada, Alexandre Marquet.
Implementation Notes
--------------------
**Hardware:**
* Adafruit `SGP30 Air Quality Sensor Breakout - VOC and eCO2
<https://www.adafruit.com/product/3709>`_ (Product ID: 3709)
**Software and Dependencies:**
* MicroPython:
https://github.com/micropython/micropython
* Modified by Alan Peaty for MicroPython port.
"""
from math import exp
from utime import sleep_ms
from micropython import const
# General SGP30 settings
SGP30_DEFAULT_I2C_ADDR = const(0x58)
SGP30_WORD_LEN = const(2)
SGP30_CRC8_POLYNOMIAL = const(0x31)
SGP30_CRC8_INIT = const(0xFF)
SGP30_CRC8_FINAL_XOR = const(0xFF)
SGP30_MEASURE_TEST_PASS = const(0xD400)
# SGP30 feature set measurement commands (Hex Codes)
# From datasheet section 6.3
SGP30_CMD_IAQ_INIT_HEX = [0x20, 0x03]
SGP30_CMD_IAQ_INIT_WORDS = const(0)
SGP30_CMD_IAQ_INIT_MAX_MS = const(10)
SGP30_CMD_MEASURE_IAQ_HEX = [0x20, 0x08]
SGP30_CMD_MEASURE_IAQ_WORDS = const(2)
SGP30_CMD_MEASURE_IAQ_MS = const(12)
SGP30_CMD_GET_IAQ_BASELINE_HEX = [0x20, 0x15]
SGP30_CMD_GET_IAQ_BASELINE_WORDS = const(2)
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS = const(10)
SGP30_CMD_SET_IAQ_BASELINE_HEX = [0x20, 0x1E]
SGP30_CMD_SET_IAQ_BASELINE_WORDS = const(0)
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS = const(10)
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX = [0x20, 0x61]
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS = const(0)
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS = const(10)
SGP30_CMD_MEASURE_TEST_HEX = [0x20, 0x32]
SGP30_CMD_MEASURE_TEST_WORDS = const(1)
SGP30_CMD_MEASURE_TEST_MAX_MS = const(220)
SGP30_CMD_GET_FEATURE_SET_HEX = [0x20, 0x2F]
SGP30_CMD_GET_FEATURE_SET_WORDS = const(1)
SGP30_CMD_GET_FEATURE_SET_MAX_MS = const(10)
SGP30_CMD_MEASURE_RAW_HEX = [0x20, 0x50]
SGP30_CMD_MEASURE_RAW_WORDS = const(2)
SGP30_CMD_MEASURE_RAW_MAX_MS = const(25)
SGP30_CMD_GET_TVOC_INCEPTIVE_HEX = [0x20, 0xB3]
SGP30_CMD_GET_TVOC_INCEPTIVE_WORDS = const(1)
SGP30_CMD_GET_TVOC_INCEPTIVE_MAX_MS = const(10)
SGP30_CMD_SET_TVOC_BASELINE_HEX = [0x20, 0x77]
SGP30_CMD_SET_TVOC_BASELINE_WORDS = const(0)
SGP30_CMD_SET_TVOC_BASELINE_MAX_MS = const(10)
# TODO: Soft Reset (datasheet section 6.4)
# Obtaining Serial ID (datasheet section 6.5)
SGP30_CMD_GET_SERIAL_ID_HEX = [0x36, 0x82]
SGP30_CMD_GET_SERIAL_ID_WORDS = const(3)
SGP30_CMD_GET_SERIAL_ID_MAX_MS = const(10)
class SGP30:
"""
A driver for the SGP30 gas sensor.
:param i2c: The "I2C" object to use. This is the only required parameter.
:param int address: (optional) The I2C address of the device.
:param boolean measure_test: (optional) Whether to run on-chip test during initialisation.
:param boolean iaq_init: (optional) Whether to initialise SGP30 algorithm / baseline.
"""
def __init__(
self, i2c, addr=SGP30_DEFAULT_I2C_ADDR, measure_test=False, iaq_init=True
):
""" Initialises the sensor and display stats """
self._i2c = i2c
if addr not in self._i2c.scan():
raise IOError("No SGP30 device found on I2C bus")
self.addr = addr
self.serial = self.get_serial()
self.feature_set = self.get_feature_set()
if measure_test:
if SGP30_MEASURE_TEST_PASS != self.measure_test():
raise RuntimeError("Device failed the on-chip test")
print(
"SGP30 device discovered...\n"
+ "I2C address: "
+ str(self.addr)
+ "\n"
+ "Serial ID: "
+ str(self.serial)
+ "\n"
+ "Feature set: "
+ str(self.feature_set)
+ "\n"
+ "Initialise algo: "
+ str(iaq_init)
)
if iaq_init:
self.iaq_init()
def iaq_init(self):
""" Initialises the IAQ algorithm """
self._i2c_read_words_from_cmd(
SGP30_CMD_IAQ_INIT_HEX, SGP30_CMD_IAQ_INIT_MAX_MS, SGP30_CMD_IAQ_INIT_WORDS
)
def measure_iaq(self):
""" Measures the CO2eq and TVOC """
return self._i2c_read_words_from_cmd(
SGP30_CMD_MEASURE_IAQ_HEX,
SGP30_CMD_MEASURE_IAQ_MS,
SGP30_CMD_MEASURE_IAQ_WORDS,
)
def get_iaq_baseline(self):
""" Retreives the IAQ algorithm baseline for CO2eq and TVOC """
return self._i2c_read_words_from_cmd(
SGP30_CMD_GET_IAQ_BASELINE_HEX,
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS,
SGP30_CMD_GET_IAQ_BASELINE_WORDS,
)
def set_iaq_baseline(self, co2eq, tvoc):
""" Sets the previously recorded IAQ algorithm baseline for CO2eq and TVOC """
if co2eq == 0 and tvoc == 0:
raise ValueError("Invalid baseline values used")
buffer = []
for value in [tvoc, co2eq]:
arr = [value >> 8, value & 0xFF]
arr.append(generate_crc(arr))
buffer += arr
self._i2c_read_words_from_cmd(
SGP30_CMD_SET_IAQ_BASELINE_HEX + buffer,
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS,
SGP30_CMD_SET_IAQ_BASELINE_WORDS,
)
def set_absolute_humidity(self, absolute_humidity):
""" Sets absolute humidity compensation. To disable,
set 0. """
buffer = []
arr = [absolute_humidity >> 8, absolute_humidity & 0xFF]
arr.append(generate_crc(arr))
buffer += arr
self._i2c_read_words_from_cmd(
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX + buffer,
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS,
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS,
)
def measure_test(self):
""" Runs on-chip self test """
return self._i2c_read_words_from_cmd(
SGP30_CMD_MEASURE_TEST_HEX,
SGP30_CMD_MEASURE_TEST_MAX_MS,
SGP30_CMD_MEASURE_TEST_WORDS,
)[0]
def get_feature_set(self):
""" Retrieves feature set of sensor """
return self._i2c_read_words_from_cmd(
SGP30_CMD_GET_FEATURE_SET_HEX,
SGP30_CMD_GET_FEATURE_SET_MAX_MS,
SGP30_CMD_GET_FEATURE_SET_WORDS,
)[0]
def measure_raw(self):
""" Returns raw H2 and Ethanol signals, used for part verification and testing """
return self._i2c_read_words_from_cmd(
SGP30_CMD_MEASURE_RAW_HEX,
SGP30_CMD_MEASURE_RAW_MAX_MS,
SGP30_CMD_MEASURE_RAW_WORDS,
)
# TODO: Get TVOC inceptive baseline
# TODO: Set TVOC baseline
# TODO: Soft Reset (datasheet section 6.4)
def get_serial(self):
""" Retrieves sensor serial """
serial = self.serial = self._i2c_read_words_from_cmd(
SGP30_CMD_GET_SERIAL_ID_HEX,
SGP30_CMD_GET_SERIAL_ID_MAX_MS,
SGP30_CMD_GET_SERIAL_ID_WORDS,
)
return hex(int.from_bytes(bytearray(serial), "large"))
@property
def co2eq(self):
""" Carbon Dioxide Equivalent in parts per million (ppm) """
return self.measure_iaq()[0]
@property
def baseline_co2eq(self):
""" Carbon Dioxide Equivalent baseline value """
return self.get_iaq_baseline()[0]
@property
def tvoc(self):
""" Total Volatile Organic Compound in parts per billion (ppb) """
return self.measure_iaq()[1]
@property
def baseline_tvoc(self):
""" Total Volatile Organic Compound baseline value """
return self.get_iaq_baseline()[1]
@property
def raw_h2(self):
""" Raw H2 signal """
return self.measure_raw()[0]
@property
def raw_ethanol(self):
""" Raw Ethanol signal """
return self.measure_raw()[1]
def _i2c_read_words_from_cmd(self, command, delay, reply_size):
""" Runs an SGP command query, gets a reply and CRC results if necessary """
self._i2c.writeto(self.addr, bytes(command))
sleep_ms(delay)
if not reply_size:
return None
crc_result = bytearray(reply_size * (SGP30_WORD_LEN + 1))
self._i2c.readfrom_into(self.addr, crc_result)
result = []
for i in range(reply_size):
word = [crc_result[3 * i], crc_result[3 * i + 1]]
crc = crc_result[3 * i + 2]
if generate_crc(word) != crc:
raise RuntimeError("CRC Error")
result.append(word[0] << 8 | word[1])
return result
def generate_crc(data):
""" 8-bit CRC algorithm for checking data.
Calculation described in section 6.6 of SGP30 datasheet """
crc = SGP30_CRC8_INIT
# Calculates 8-Bit CRC checksum with given polynomial
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x80:
crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL
else:
crc <<= 1
return crc & 0xFF
def convert_r_to_a_humidity(temp_c, r_humidity_perc, fixed_point=True):
""" Converts relative to absolute humidity as per the equation
found in datasheet """
a_humidity_gm3 = 216.7 * (
(r_humidity_perc / 100 * 6.112 * exp(17.62 * temp_c / (243.12 + temp_c)))
/ (273.15 + temp_c)
)
# Return in 8.8 bit fixed point format (for setting humidity compensation), if not
# simply return the calculated value in g/m^3
if fixed_point:
a_humidity_gm3 = (int(a_humidity_gm3) << 8) + (int(a_humidity_gm3 % 1 * 256))
return a_humidity_gm3

View File

@ -0,0 +1,86 @@
# Importe tout les modules requis
from machine import Pin, I2C, UART
import uSGP30
import uBME280
from i2c_lcd import lcd
import time
# Défini l'interface du protocole I2C
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 1024)
# Défini l'interface UART utilisée pour le Bluetooth
BT = UART(1, baudrate = 9600, tx = Pin(4), rx = Pin(5))
# Défuini les adresses I2C requis pour les capteurs
BME_addr = 0x76;
SGP30_adrr = 0x58;
# Déclare les paramètres des capteurs
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
# Le BME280 prends comme argument : le mode du capteur, l'adresse i2c du capteur et l'interface du protocole i2c
sgp30 = uSGP30.SGP30(i2c, SGP30_adrr)
# Le SGP30 prends comme argument : l'interface du protocole i2c et l'adresse i2c du capteur
display = lcd(i2c)
# Crée les variables contenants les valeurs extérieures
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
# Les valeurs ci dessus doivent être converties en texte car l'écran requiers des valeurs car sinon le programe renvoie une "TypeError: object with buffer protocol required"
# De plus, les valeurs doivent êtres divisés par 100 ou par 1000 car elles ne sont pas dans la bonne unitée (capteur en pascal, valeur attendue en kPascal)
t_CO2, t_COV = sgp30.measure_iaq()
co2 = str(t_CO2)
# Crée la fonction qui permet de récupérer les valeurs
def Update_Valeurs():
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
t_CO2, t_COV = sgp30.measure_iaq()
co2 = str(t_CO2)
# Crée la fonction qui permet d'afficher le "premier écran"
def First_Screen():
# Affiche le premier "écran" (Température + Humidité)
display.home()
display.write("Temp = ")
display.write(t)
display.write(" °C")
display.setCursor(0,1)
display.write("THum = ")
display.write(h)
display.write(" %")
# Crée la fonction qui permet d'afficher le "deuxième écran"
def Second_Screen():
# Affiche le deuxième "écran" (Pression + CO2)
display.clear()
display.home()
display.write("P = ")
display.write(p)
display.write(" Pa")
display.setCursor(0,1)
display.write("TCO2 = ")
display.write(co2)
display.write(" ppm")
# Crée la fonction qui permet d'afficher les valeurs
def Update_Screen():
# Affiche le premier "écran"
First_Screen()
time.sleep(5)
Second_Screen()
time.sleep(5)
display.clear()
# Crée la fonction qui permet d'envoyer les valeurs en bluetooth
def Send_Datas(a, b, c, d):
BT.write(a)
BT.write(b)
BT.write(c)
BT.write(d)
# Lance le programme indéfiniment
while True:
Update_Valeurs()
Send_Datas(t, h, p, co2)
Update_Screen()

View File

@ -0,0 +1,24 @@
{
"nodes":[
{"id":"ef10e0e9de432d66","type":"text","text":"Carte raspberry PICO\n","x":-210,"y":-196,"width":250,"height":50,"color":"1"},
{"id":"078d5b19fbbc6b3e","type":"text","text":"Début ou fin","x":640,"y":-420,"width":250,"height":50,"color":"1"},
{"id":"781a281c217a87e4","type":"text","text":"Traitement","x":640,"y":-340,"width":250,"height":50,"color":"3"},
{"id":"b154f88c8da852f4","type":"text","text":"Entrée/sortie","x":640,"y":-251,"width":250,"height":55,"color":"6"},
{"id":"fa87106ca6ca9685","x":-210,"y":-39,"width":250,"height":60,"color":"3","type":"text","text":"Update_Values()"},
{"id":"59f59b8b9806b549","x":-210,"y":420,"width":250,"height":60,"color":"3","type":"text","text":"Conversion des valeurs brutes"},
{"id":"c08d9840e4f49bf2","x":-210,"y":650,"width":250,"height":60,"color":"3","type":"text","text":"Affichage des valeurs"},
{"id":"25b4fe07f6d1c2a6","x":-210,"y":200,"width":250,"height":60,"color":"6","type":"text","text":"BME280"},
{"id":"f9be99f4a13e5d26","x":80,"y":200,"width":234,"height":60,"color":"6","type":"text","text":"SGP30"},
{"id":"928adab9542314a4","x":189,"y":655,"width":250,"height":50,"color":"6","type":"text","text":"Ecran LCD"}
],
"edges":[
{"id":"bec9ba33e0fdedcc","fromNode":"ef10e0e9de432d66","fromSide":"bottom","toNode":"fa87106ca6ca9685","toSide":"top"},
{"id":"7f8ddcc682e8421c","fromNode":"fa87106ca6ca9685","fromSide":"bottom","toNode":"25b4fe07f6d1c2a6","toSide":"top"},
{"id":"8a56bb625d58db96","fromNode":"fa87106ca6ca9685","fromSide":"bottom","toNode":"f9be99f4a13e5d26","toSide":"top"},
{"id":"f340551ea5272ac2","fromNode":"25b4fe07f6d1c2a6","fromSide":"bottom","toNode":"59f59b8b9806b549","toSide":"top"},
{"id":"315d366bc4490e22","fromNode":"f9be99f4a13e5d26","fromSide":"bottom","toNode":"59f59b8b9806b549","toSide":"top"},
{"id":"176c34e7ba2b699e","fromNode":"59f59b8b9806b549","fromSide":"bottom","toNode":"c08d9840e4f49bf2","toSide":"top"},
{"id":"b0b97834bda7aa82","fromNode":"c08d9840e4f49bf2","fromSide":"right","toNode":"928adab9542314a4","toSide":"left"},
{"id":"6414806d66e6db2a","fromNode":"c08d9840e4f49bf2","fromSide":"left","toNode":"fa87106ca6ca9685","toSide":"left"}
]
}

View File

@ -0,0 +1,15 @@
from machine import Pin, UART
import time
BT = UART(1, baudrate = 9600, tx = Pin(4), rx = Pin(5))
"""
compteur = 0
BT = UART(1, 9600)
BT.init(baudrate=9600, tx = Pin(4), rx = Pin(5))
"""
toto=("hello")
while True:
BT.write(toto+'\n')
time.sleep(1)

View File

@ -0,0 +1,17 @@
from machine import Pin, I2C
import uBME280
import time
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
BME_addr = 0x76;
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
while True:
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
time.sleep(1)
print(t, p, h)

View File

@ -0,0 +1,9 @@
from machine import Pin, I2C
from i2c_lcd import lcd
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
display = lcd(i2c)
display.home()
display.write("Temp = ")

View File

@ -0,0 +1,14 @@
from machine import Pin, I2C
import uSGP30
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
SGP30_addr = 0x58;
# sgp30 = uSGP30.SGP30(i2c, SGP30_addr);
sgp30 = uSGP30.SGP30(i2c)
t_CO2, t_COV = sgp30.measure_iaq()
print(t_CO2)

View File

@ -0,0 +1,26 @@
# Importe tout les modules requis
from machine import Pin, I2C
import uSGP30
import uBME280
from i2c_lcd import lcd
import time
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
BME_addr = 0x76;
ptr_registre = 0
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
display = lcd(i2c)
while True:
t = bme280.read_temperature()/100
p = bme280.read_pressure()/1000
h = bme280.read_humidity()/1000
print(t, "°C")
# print(p, "hPascals")
print(h, "%")
display.write('Bouh')
display.cursor(1)
time.sleep(1)
display.clear()

View File

@ -0,0 +1,68 @@
import network
import time
import socket
def web_page():
html = """<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
<!-- Begin
function reFresh() {
location.reload(true)
}
/* Definir le temp de refraichir le nombre en in milliseconds, 1 minute = 60000 milliseconds. */
window.setInterval("reFresh()",500);
// End -->
</script>
</head>
<body>
<h1>Weather Station</h1>
<p>Temperature : {t}</p>
<p>Pression Atmoshérique : {p}</p>
<p>Humiditée : {h}</p>
<p>Taux de CO2 : {co2}</p>
</body>
</html>
"""
return html
# if you do not see the network you may have to power cycle
# unplug your pico w for 10 seconds and plug it in again
def ap_mode(ssid, password):
"""
Description: This is a function to activate AP mode
Parameters:
ssid[str]: The name of your internet connection
password[str]: Password for your internet connection
Returns: Nada
"""
# Just making our internet connection
ap = network.WLAN(network.AP_IF)
ap.config(essid=ssid, password=password)
ap.active(True)
while ap.active() == False:
pass
print('AP Mode Is Active, You can Now Connect')
print('IP Address To Connect to:: ' + ap.ifconfig()[0])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #creating socket object
s.bind(('', 80))
s.listen(5)
while True:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
print('Content = %s' % str(request))
response = web_page()
conn.send(response)
conn.close()
ap_mode('Weather Station',
'Miam1234')

View File

@ -0,0 +1,21 @@
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
<!-- Begin
function reFresh() {
location.reload(true)
}
/* Definir le temp de refraichir le nombre en in milliseconds, 1 minute = 60000 milliseconds. */
window.setInterval("reFresh()",500);
// End -->
</script>
</head>
<body>
<h1>Weather Station</h1>
<p>Temperature : {t}</p>
<p>Pression Atmoshérique : {p}</p>
<p>Humiditée : {h}</p>
<p>Taux de CO2 : {co2}</p>
</body>
</html>

View File

@ -0,0 +1,56 @@
# Importe tout les modules requis
from machine import Pin, I2C
import uSGP30
import uBME280
from i2c_lcd import lcd
import time
import network
import socket
# Défini l'interface du protocole I2C
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 1024)
# Défini l'adresse I2C requis pour les capteurs
BME_addr = 0x76;
SGP30_addr = 0x58;
# Déclare les paramètres dans des variables
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
sgp30 = uSGP30.SGP30(i2c, SGP30_addr);
display = lcd(i2c)
def Update():
# Récupère toutes les données du capteur BME280
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
t_CO2, t_COV = sgp30.measure_iaq()
co2 = str(t_CO2)
# Affiche la première image (Température + Humidité)
display.home()
display.write("Temp = ")
display.write(t)
display.write(" °C")
display.setCursor(0,1)
display.write("Hum = ")
display.write(h)
display.write(" %")
time.sleep(5)
# Affiche la deuxième image (Pression + CO2)
display.clear()
display.home()
display.write("P = ")
display.write(p)
display.write(" Pa")
display.setCursor(0,1)
display.write("TCO2 = ")
display.write(co2)
display.write(" ppm")
f = open("demofile1.txt", "w")
f.write(t)
f.close()
time.sleep(5)
display.clear()
while True:
Update()

View File

@ -0,0 +1,5 @@
from machine import SoftI2C, Pin
i2c=SoftI2C(sda=Pin(20), scl=Pin(21), freq=400000)
scan = i2c.scan()
print(scan)
print(i2c.readfrom_mem(0x76, 0xd0, 1)[0])

View File

@ -0,0 +1,3 @@
from machine import SoftI2C, Pin
i2c=SoftI2C(sda=Pin(20), scl=Pin(21), freq=400000)
print(i2c.readfrom_mem(0x76, 0xd0, 1)[0])

View File

@ -0,0 +1,14 @@
from machine import Pin,UART
uart = UART(0,9600)
LedGPIO = 16
led = Pin(LedGPIO, Pin.OUT)
while True:
if uart.any():
command = uart.readline()
print(command) # uncomment this line to see the recieved data
if command==b'\xd0':
led.high()
print("ON")
elif command==b'\xd5':
led.low()
print("OFF")

View File

@ -0,0 +1,123 @@
# Importe tout les modules requis
from machine import Pin, I2C
import uSGP30
import uBME280
from i2c_lcd import lcd
import time
import network
import socket
# Défini l'interface du protocole I2C
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
# Défini l'adresse I2C requis pour les capteurs
BME_addr = 0x76;
SGP30_addr = 0x58;
# Déclare les paramètres dans des variables
bme280 = uBME280.BME280(uBME280.BME280_OSAMPLE_1, BME_addr, i2c)
sgp30 = uSGP30.SGP30(i2c, SGP30_addr);
display = lcd(i2c)
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
t_CO2, t_COV = sgp30.measure_iaq()
co2 = str(t_CO2)
def Update():
# Récupère toutes les données du capteur BME280
t = str(bme280.read_temperature()/100)
p = str(bme280.read_pressure()/1000)
h = str(bme280.read_humidity()/1000)
t_CO2, t_COV = sgp30.measure_iaq()
co2 = str(t_CO2)
# Affiche la première image (Température + Humidité)
display.home()
display.write("Temp = ")
display.write(t)
display.write(" °C")
display.setCursor(0,1)
display.write("THum = ")
display.write(h)
display.write(" %")
time.sleep(1.5)
# Affiche la deuxième image (Pression + CO2)
display.clear()
display.home()
display.write("P = ")
display.write(p)
display.write(" Pa")
display.setCursor(0,1)
display.write("TCO2 = ")
display.write(co2)
display.write(" ppm")
time.sleep(1.5)
display.clear()
def web_page():
html = """<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script type="text/javascript">
<!-- Begin
function reFresh() {
location.reload(true)
}
/* Definir le temp de refraichir le nombre en in milliseconds, 1 minute = 60000 milliseconds. */
window.setInterval("reFresh()",500);
// End -->
</script>
</head>
<body>
<h1>Weather Station</h1>
<p>Temperature : {t}</p>
<p>Pression Atmoshérique : {p}</p>
<p>Humiditée : {h}</p>
<p>Taux de CO2 : {co2}</p>
</body>
</html>
"""
return html
# if you do not see the network you may have to power cycle
# unplug your pico w for 10 seconds and plug it in again
def ap_mode(ssid, password):
"""
Description: This is a function to activate AP mode
Parameters:
ssid[str]: The name of your internet connection
password[str]: Password for your internet connection
Returns: Nada
"""
# Just making our internet connection
ap = network.WLAN(network.AP_IF)
ap.config(essid=ssid, password=password)
ap.active(True)
while ap.active() == False:
pass
print('AP Mode Is Active, You can Now Connect')
print('IP Address To Connect to:: ' + ap.ifconfig()[0])
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) #creating socket object
s.bind(('', 80))
s.listen(5)
while True:
conn, addr = s.accept()
print('Got a connection from %s' % str(addr))
request = conn.recv(1024)
print('Content = %s' % str(request))
Update()
response = web_page()
conn.send(response)
conn.close()
ap_mode('Weather Station',
'Miam1234')

View File

@ -0,0 +1,58 @@
import machine, time, _thread
from machine import Timer
from machine import Pin, I2C
from i2c_lcd import lcd
i2c = I2C(0, scl = Pin(9), sda = Pin(8), freq = 400000)
display = lcd(i2c)
#led interne du raspberry pico
pico_led = machine.Pin(25, machine.Pin.OUT)
# Objet compte à rebours
class CptRebours():
#constructeur, initialise timeleft
def __init__(self, t=0):
self.timeleft = t
# fct callbackappelée par le timer
def countdown(self, tm):
if self.timeleft > 0 :
self.timeleft -= 1
# Fonction exécutée dans le second thread
# gère le clignotement de la led
def thread_anim():
while True:
if (cptr.timeleft>0):
# fait clignoter la led interne
pico_led.toggle()
display.home()
display.write("Temp = ")
# attente supplémentaire s'il reste plus de 5s
if cptr.timeleft>5:
time.sleep(0.18)
else:
# extinction de la led interne
pico_led.value(0)
# temps d'attente clignotement
time.sleep(0.18)
#initialisation d'un compte à rebours
cptr = CptRebours()
#démarrage du thread d'animation
_thread.start_new_thread(thread_anim, ())
#boucle du thread principal
while True:
cptr = CptRebours(int(input("Compte à rebours en secondes: ")))
print('Démarrage compte à rebours ...')
tim = Timer(period=1000, callback=cptr.countdown)
while (cptr.timeleft > 0 ):
print('temps restant:', cptr.timeleft, ' secondes')
time.sleep(1)
print("BIP BIP BIP compte à rebours terminé !")
tim.deinit() #stoppe et libère le timer

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@ -0,0 +1,135 @@
from machine import I2C
import time
_I2CADDR = const(0x3E)
# commands
_LCD_CLEARDISPLAY = const(0x01)
_LCD_RETURNHOME = const(0x02)
_LCD_ENTRYMODESET = const(0x04)
_LCD_DISPLAYCONTROL = const(0x08)
_LCD_CURSORSHIFT = const(0x10)
_LCD_FUNCTIONSET = const(0x20)
_LCD_SETCGRAMADDR = const(0x40)
_LCD_SETDDRAMADDR = const(0x80)
# flags for display entry mode
_LCD_ENTRYRIGHT = const(0x00)
_LCD_ENTRYLEFT = const(0x02)
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
# flags for display on/off control
_LCD_DISPLAYON = const(0x04)
_LCD_DISPLAYOFF = const(0x00)
_LCD_CURSORON = const(0x02)
_LCD_CURSOROFF = const(0x00)
_LCD_BLINKON = const(0x01)
_LCD_BLINKOFF = const(0x00)
# flags for display/cursor shift
_LCD_DISPLAYMOVE = const(0x08)
_LCD_CURSORMOVE = const(0x00)
_LCD_MOVERIGHT = const(0x04)
_LCD_MOVELEFT = const(0x00)
# flags for function set
_LCD_8BITMODE = const(0x10)
_LCD_4BITMODE = const(0x00)
_LCD_2LINE = const(0x08)
_LCD_1LINE = const(0x00)
_LCD_5x10DOTS = const(0x04)
_LCD_5x8DOTS = const(0x00)
class lcd:
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
self.i2c = i2c
self.i2c.scan()
self.address = address
self.disp_func = _LCD_DISPLAYON
if not oneline:
self.disp_func |= _LCD_2LINE
elif charsize != 0:
# for 1-line displays you can choose another dotsize
self.disp_func |= _LCD_5x10DOTS
# wait for display init after power-on
time.sleep_ms(50) # 50ms
# send function set
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
# turn on the display
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
self.display(True)
# clear it
self.clear()
# set default text direction (left-to-right)
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
def cmd(self, command):
assert command >= 0 and command < 256
command = bytearray([command])
self.i2c.writeto_mem(self.address, 0x80, command)
def write_char(self, c):
assert c >= 0 and c < 256
c = bytearray([c])
self.i2c.writeto_mem(self.address, 0x40, c)
def write(self, text):
for char in text:
self.write_char(ord(char))
def cursor(self, state):
if state:
self.disp_ctrl |= _LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def setCursor(self, col, row):
col = (col | 0x80) if row == 0 else (col | 0xc0)
self.cmd(col)
def autoscroll(self, state):
if state:
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def blink(self, state):
if state:
self.disp_ctrl |= _LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def display(self, state):
if state:
self.disp_ctrl |= _LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def clear(self):
self.cmd(_LCD_CLEARDISPLAY)
time.sleep_ms(2) # 2ms
def home(self):
self.cmd(_LCD_RETURNHOME)
time.sleep_ms(2) # 2m

View File

@ -0,0 +1,135 @@
from machine import I2C
import time
_I2CADDR = const(0x3E)
# commands
_LCD_CLEARDISPLAY = const(0x01)
_LCD_RETURNHOME = const(0x02)
_LCD_ENTRYMODESET = const(0x04)
_LCD_DISPLAYCONTROL = const(0x08)
_LCD_CURSORSHIFT = const(0x10)
_LCD_FUNCTIONSET = const(0x20)
_LCD_SETCGRAMADDR = const(0x40)
_LCD_SETDDRAMADDR = const(0x80)
# flags for display entry mode
_LCD_ENTRYRIGHT = const(0x00)
_LCD_ENTRYLEFT = const(0x02)
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
# flags for display on/off control
_LCD_DISPLAYON = const(0x04)
_LCD_DISPLAYOFF = const(0x00)
_LCD_CURSORON = const(0x02)
_LCD_CURSOROFF = const(0x00)
_LCD_BLINKON = const(0x01)
_LCD_BLINKOFF = const(0x00)
# flags for display/cursor shift
_LCD_DISPLAYMOVE = const(0x08)
_LCD_CURSORMOVE = const(0x00)
_LCD_MOVERIGHT = const(0x04)
_LCD_MOVELEFT = const(0x00)
# flags for function set
_LCD_8BITMODE = const(0x10)
_LCD_4BITMODE = const(0x00)
_LCD_2LINE = const(0x08)
_LCD_1LINE = const(0x00)
_LCD_5x10DOTS = const(0x04)
_LCD_5x8DOTS = const(0x00)
class lcd:
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
self.i2c = i2c
self.i2c.scan()
self.address = address
self.disp_func = _LCD_DISPLAYON
if not oneline:
self.disp_func |= _LCD_2LINE
elif charsize != 0:
# for 1-line displays you can choose another dotsize
self.disp_func |= _LCD_5x10DOTS
# wait for display init after power-on
time.sleep_ms(50) # 50ms
# send function set
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
# turn on the display
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
self.display(True)
# clear it
self.clear()
# set default text direction (left-to-right)
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
def cmd(self, command):
assert command >= 0 and command < 256
command = bytearray([command])
self.i2c.writeto_mem(self.address, 0x80, command)
def write_char(self, c):
assert c >= 0 and c < 256
c = bytearray([c])
self.i2c.writeto_mem(self.address, 0x40, c)
def write(self, text):
for char in text:
self.write_char(ord(char))
def cursor(self, state):
if state:
self.disp_ctrl |= _LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def setCursor(self, col, row):
col = (col | 0x80) if row == 0 else (col | 0xc0)
self.cmd(col)
def autoscroll(self, state):
if state:
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def blink(self, state):
if state:
self.disp_ctrl |= _LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def display(self, state):
if state:
self.disp_ctrl |= _LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def clear(self):
self.cmd(_LCD_CLEARDISPLAY)
time.sleep_ms(2) # 2ms
def home(self):
self.cmd(_LCD_RETURNHOME)
time.sleep_ms(2) # 2m

View File

@ -0,0 +1,284 @@
from machine import I2C
import time
# BME280 default address.
BME280_I2CADDR = 0x76
# Operating Modes
BME280_OSAMPLE_1 = 1
BME280_OSAMPLE_2 = 2
BME280_OSAMPLE_4 = 3
BME280_OSAMPLE_8 = 4
BME280_OSAMPLE_16 = 5
# BME280 Registers
BME280_REGISTER_DIG_T1 = 0x88 # Trimming parameter registers
BME280_REGISTER_DIG_T2 = 0x8A
BME280_REGISTER_DIG_T3 = 0x8C
BME280_REGISTER_DIG_P1 = 0x8E
BME280_REGISTER_DIG_P2 = 0x90
BME280_REGISTER_DIG_P3 = 0x92
BME280_REGISTER_DIG_P4 = 0x94
BME280_REGISTER_DIG_P5 = 0x96
BME280_REGISTER_DIG_P6 = 0x98
BME280_REGISTER_DIG_P7 = 0x9A
BME280_REGISTER_DIG_P8 = 0x9C
BME280_REGISTER_DIG_P9 = 0x9E
BME280_REGISTER_DIG_H1 = 0xA1
BME280_REGISTER_DIG_H2 = 0xE1
BME280_REGISTER_DIG_H3 = 0xE3
BME280_REGISTER_DIG_H4 = 0xE4
BME280_REGISTER_DIG_H5 = 0xE5
BME280_REGISTER_DIG_H6 = 0xE6
BME280_REGISTER_DIG_H7 = 0xE7
BME280_REGISTER_CHIPID = 0xD0
BME280_REGISTER_VERSION = 0xD1
BME280_REGISTER_SOFTRESET = 0xE0
BME280_REGISTER_CONTROL_HUM = 0xF2
BME280_REGISTER_CONTROL = 0xF4
BME280_REGISTER_CONFIG = 0xF5
BME280_REGISTER_PRESSURE_DATA = 0xF7
BME280_REGISTER_TEMP_DATA = 0xFA
BME280_REGISTER_HUMIDITY_DATA = 0xFD
class Device:
"""Class for communicating with an I2C device.
Allows reading and writing 8-bit, 16-bit, and byte array values to
registers on the device."""
def __init__(self, address, i2c):
"""Create an instance of the I2C device at the specified address using
the specified I2C interface object."""
self._address = address
self._i2c = i2c
def writeRaw8(self, value):
"""Write an 8-bit value on the bus (without register)."""
value = value & 0xFF
self._i2c.writeto(self._address, value)
def write8(self, register, value):
"""Write an 8-bit value to the specified register."""
b=bytearray(1)
b[0]=value & 0xFF
self._i2c.writeto_mem(self._address, register, b)
def write16(self, register, value):
"""Write a 16-bit value to the specified register."""
value = value & 0xFFFF
b=bytearray(2)
b[0]= value & 0xFF
b[1]= (value>>8) & 0xFF
self.i2c.writeto_mem(self._address, register, value)
def readRaw8(self):
"""Read an 8-bit value on the bus (without register)."""
return int.from_bytes(self._i2c.readfrom(self._address, 1),'little') & 0xFF
def readU8(self, register):
"""Read an unsigned byte from the specified register."""
return int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 1),'little') & 0xFF
def readS8(self, register):
"""Read a signed byte from the specified register."""
result = self.readU8(register)
if result > 127:
result -= 256
return result
def readU16(self, register, little_endian=True):
"""Read an unsigned 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = int.from_bytes(
self._i2c.readfrom_mem(self._address, register, 2),'little') & 0xFFFF
if not little_endian:
result = ((result << 8) & 0xFF00) + (result >> 8)
return result
def readS16(self, register, little_endian=True):
"""Read a signed 16-bit value from the specified register, with the
specified endianness (default little endian, or least significant byte
first)."""
result = self.readU16(register, little_endian)
if result > 32767:
result -= 65536
return result
def readU16LE(self, register):
"""Read an unsigned 16-bit value from the specified register, in little
endian byte order."""
return self.readU16(register, little_endian=True)
def readU16BE(self, register):
"""Read an unsigned 16-bit value from the specified register, in big
endian byte order."""
return self.readU16(register, little_endian=False)
def readS16LE(self, register):
"""Read a signed 16-bit value from the specified register, in little
endian byte order."""
return self.readS16(register, little_endian=True)
def readS16BE(self, register):
"""Read a signed 16-bit value from the specified register, in big
endian byte order."""
return self.readS16(register, little_endian=False)
class BME280:
def __init__(self, mode=BME280_OSAMPLE_1, address=BME280_I2CADDR, i2c=None,
**kwargs):
# Check that mode is valid.
if mode not in [BME280_OSAMPLE_1, BME280_OSAMPLE_2, BME280_OSAMPLE_4,
BME280_OSAMPLE_8, BME280_OSAMPLE_16]:
raise ValueError(
'Unexpected mode value {0}. Set mode to one of '
'BME280_ULTRALOWPOWER, BME280_STANDARD, BME280_HIGHRES, or '
'BME280_ULTRAHIGHRES'.format(mode))
self._mode = mode
# Create I2C device.
if i2c is None:
raise ValueError('An I2C object is required.')
self._device = Device(address, i2c)
# Load calibration values.
self._load_calibration()
self._device.write8(BME280_REGISTER_CONTROL, 0x3F)
self.t_fine = 0
def _load_calibration(self):
self.dig_T1 = self._device.readU16LE(BME280_REGISTER_DIG_T1)
self.dig_T2 = self._device.readS16LE(BME280_REGISTER_DIG_T2)
self.dig_T3 = self._device.readS16LE(BME280_REGISTER_DIG_T3)
self.dig_P1 = self._device.readU16LE(BME280_REGISTER_DIG_P1)
self.dig_P2 = self._device.readS16LE(BME280_REGISTER_DIG_P2)
self.dig_P3 = self._device.readS16LE(BME280_REGISTER_DIG_P3)
self.dig_P4 = self._device.readS16LE(BME280_REGISTER_DIG_P4)
self.dig_P5 = self._device.readS16LE(BME280_REGISTER_DIG_P5)
self.dig_P6 = self._device.readS16LE(BME280_REGISTER_DIG_P6)
self.dig_P7 = self._device.readS16LE(BME280_REGISTER_DIG_P7)
self.dig_P8 = self._device.readS16LE(BME280_REGISTER_DIG_P8)
self.dig_P9 = self._device.readS16LE(BME280_REGISTER_DIG_P9)
self.dig_H1 = self._device.readU8(BME280_REGISTER_DIG_H1)
self.dig_H2 = self._device.readS16LE(BME280_REGISTER_DIG_H2)
self.dig_H3 = self._device.readU8(BME280_REGISTER_DIG_H3)
self.dig_H6 = self._device.readS8(BME280_REGISTER_DIG_H7)
h4 = self._device.readS8(BME280_REGISTER_DIG_H4)
h4 = (h4 << 24) >> 20
self.dig_H4 = h4 | (self._device.readU8(BME280_REGISTER_DIG_H5) & 0x0F)
h5 = self._device.readS8(BME280_REGISTER_DIG_H6)
h5 = (h5 << 24) >> 20
self.dig_H5 = h5 | (
self._device.readU8(BME280_REGISTER_DIG_H5) >> 4 & 0x0F)
def read_raw_temp(self):
"""Reads the raw (uncompensated) temperature from the sensor."""
meas = self._mode
self._device.write8(BME280_REGISTER_CONTROL_HUM, meas)
meas = self._mode << 5 | self._mode << 2 | 1
self._device.write8(BME280_REGISTER_CONTROL, meas)
sleep_time = 1250 + 2300 * (1 << self._mode)
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
sleep_time = sleep_time + 2300 * (1 << self._mode) + 575
time.sleep_us(sleep_time) # Wait the required time
msb = self._device.readU8(BME280_REGISTER_TEMP_DATA)
lsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_TEMP_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_pressure(self):
"""Reads the raw (uncompensated) pressure level from the sensor."""
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA)
lsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 1)
xlsb = self._device.readU8(BME280_REGISTER_PRESSURE_DATA + 2)
raw = ((msb << 16) | (lsb << 8) | xlsb) >> 4
return raw
def read_raw_humidity(self):
"""Assumes that the temperature has already been read """
"""i.e. that enough delay has been provided"""
msb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA)
lsb = self._device.readU8(BME280_REGISTER_HUMIDITY_DATA + 1)
raw = (msb << 8) | lsb
return raw
def read_temperature(self):
"""Get the compensated temperature in 0.01 of a degree celsius."""
adc = self.read_raw_temp()
var1 = ((adc >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
var2 = ((
(((adc >> 4) - self.dig_T1) * ((adc >> 4) - self.dig_T1)) >> 12) *
self.dig_T3) >> 14
self.t_fine = var1 + var2
return (self.t_fine * 5 + 128) >> 8
def read_pressure(self):
"""Gets the compensated pressure in Pascals."""
adc = self.read_raw_pressure()
var1 = self.t_fine - 128000
var2 = var1 * var1 * self.dig_P6
var2 = var2 + ((var1 * self.dig_P5) << 17)
var2 = var2 + (self.dig_P4 << 35)
var1 = (((var1 * var1 * self.dig_P3) >> 8) +
((var1 * self.dig_P2) >> 12))
var1 = (((1 << 47) + var1) * self.dig_P1) >> 33
if var1 == 0:
return 0
p = 1048576 - adc
p = (((p << 31) - var2) * 3125) // var1
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
var2 = (self.dig_P8 * p) >> 19
return ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
def read_humidity(self):
adc = self.read_raw_humidity()
# print 'Raw humidity = {0:d}'.format (adc)
h = self.t_fine - 76800
h = (((((adc << 14) - (self.dig_H4 << 20) - (self.dig_H5 * h)) +
16384) >> 15) * (((((((h * self.dig_H6) >> 10) * (((h *
self.dig_H3) >> 11) + 32768)) >> 10) + 2097152) *
self.dig_H2 + 8192) >> 14))
h = h - (((((h >> 15) * (h >> 15)) >> 7) * self.dig_H1) >> 4)
h = 0 if h < 0 else h
h = 419430400 if h > 419430400 else h
return h >> 12
@property
def temperature(self):
"Return the temperature in degrees."
t = self.read_temperature()
ti = t // 100
td = t - ti * 100
return "{}.{:02d}C".format(ti, td)
@property
def pressure(self):
"Return the temperature in hPa."
p = self.read_pressure() // 256
pi = p // 100
pd = p - pi * 100
return "{}.{:02d}hPa".format(pi, pd)
@property
def humidity(self):
"Return the humidity in percent."
h = self.read_humidity()
hi = h // 1024
hd = h * 100 // 1024 - hi * 100
return "{}.{:02d}%".format(hi, hd)

View File

@ -0,0 +1,300 @@
# The MIT License (MIT)
#
# Copyright (c) 2017 ladyada for Adafruit Industries
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_sgp30`
====================================================
I2C driver for SGP30 Sensirion VoC sensor
* Author(s): ladyada, Alexandre Marquet.
Implementation Notes
--------------------
**Hardware:**
* Adafruit `SGP30 Air Quality Sensor Breakout - VOC and eCO2
<https://www.adafruit.com/product/3709>`_ (Product ID: 3709)
**Software and Dependencies:**
* MicroPython:
https://github.com/micropython/micropython
* Modified by Alan Peaty for MicroPython port.
"""
from math import exp
from utime import sleep_ms
from micropython import const
# General SGP30 settings
SGP30_DEFAULT_I2C_ADDR = const(0x58)
SGP30_WORD_LEN = const(2)
SGP30_CRC8_POLYNOMIAL = const(0x31)
SGP30_CRC8_INIT = const(0xFF)
SGP30_CRC8_FINAL_XOR = const(0xFF)
SGP30_MEASURE_TEST_PASS = const(0xD400)
# SGP30 feature set measurement commands (Hex Codes)
# From datasheet section 6.3
SGP30_CMD_IAQ_INIT_HEX = [0x20, 0x03]
SGP30_CMD_IAQ_INIT_WORDS = const(0)
SGP30_CMD_IAQ_INIT_MAX_MS = const(10)
SGP30_CMD_MEASURE_IAQ_HEX = [0x20, 0x08]
SGP30_CMD_MEASURE_IAQ_WORDS = const(2)
SGP30_CMD_MEASURE_IAQ_MS = const(12)
SGP30_CMD_GET_IAQ_BASELINE_HEX = [0x20, 0x15]
SGP30_CMD_GET_IAQ_BASELINE_WORDS = const(2)
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS = const(10)
SGP30_CMD_SET_IAQ_BASELINE_HEX = [0x20, 0x1E]
SGP30_CMD_SET_IAQ_BASELINE_WORDS = const(0)
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS = const(10)
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX = [0x20, 0x61]
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS = const(0)
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS = const(10)
SGP30_CMD_MEASURE_TEST_HEX = [0x20, 0x32]
SGP30_CMD_MEASURE_TEST_WORDS = const(1)
SGP30_CMD_MEASURE_TEST_MAX_MS = const(220)
SGP30_CMD_GET_FEATURE_SET_HEX = [0x20, 0x2F]
SGP30_CMD_GET_FEATURE_SET_WORDS = const(1)
SGP30_CMD_GET_FEATURE_SET_MAX_MS = const(10)
SGP30_CMD_MEASURE_RAW_HEX = [0x20, 0x50]
SGP30_CMD_MEASURE_RAW_WORDS = const(2)
SGP30_CMD_MEASURE_RAW_MAX_MS = const(25)
SGP30_CMD_GET_TVOC_INCEPTIVE_HEX = [0x20, 0xB3]
SGP30_CMD_GET_TVOC_INCEPTIVE_WORDS = const(1)
SGP30_CMD_GET_TVOC_INCEPTIVE_MAX_MS = const(10)
SGP30_CMD_SET_TVOC_BASELINE_HEX = [0x20, 0x77]
SGP30_CMD_SET_TVOC_BASELINE_WORDS = const(0)
SGP30_CMD_SET_TVOC_BASELINE_MAX_MS = const(10)
# TODO: Soft Reset (datasheet section 6.4)
# Obtaining Serial ID (datasheet section 6.5)
SGP30_CMD_GET_SERIAL_ID_HEX = [0x36, 0x82]
SGP30_CMD_GET_SERIAL_ID_WORDS = const(3)
SGP30_CMD_GET_SERIAL_ID_MAX_MS = const(10)
class SGP30:
"""
A driver for the SGP30 gas sensor.
:param i2c: The "I2C" object to use. This is the only required parameter.
:param int address: (optional) The I2C address of the device.
:param boolean measure_test: (optional) Whether to run on-chip test during initialisation.
:param boolean iaq_init: (optional) Whether to initialise SGP30 algorithm / baseline.
"""
def __init__(
self, i2c, addr=SGP30_DEFAULT_I2C_ADDR, measure_test=False, iaq_init=True
):
""" Initialises the sensor and display stats """
self._i2c = i2c
if addr not in self._i2c.scan():
raise IOError("No SGP30 device found on I2C bus")
self.addr = addr
self.serial = self.get_serial()
self.feature_set = self.get_feature_set()
if measure_test:
if SGP30_MEASURE_TEST_PASS != self.measure_test():
raise RuntimeError("Device failed the on-chip test")
print(
"SGP30 device discovered...\n"
+ "I2C address: "
+ str(self.addr)
+ "\n"
+ "Serial ID: "
+ str(self.serial)
+ "\n"
+ "Feature set: "
+ str(self.feature_set)
+ "\n"
+ "Initialise algo: "
+ str(iaq_init)
)
if iaq_init:
self.iaq_init()
def iaq_init(self):
""" Initialises the IAQ algorithm """
self._i2c_read_words_from_cmd(
SGP30_CMD_IAQ_INIT_HEX, SGP30_CMD_IAQ_INIT_MAX_MS, SGP30_CMD_IAQ_INIT_WORDS
)
def measure_iaq(self):
""" Measures the CO2eq and TVOC """
return self._i2c_read_words_from_cmd(
SGP30_CMD_MEASURE_IAQ_HEX,
SGP30_CMD_MEASURE_IAQ_MS,
SGP30_CMD_MEASURE_IAQ_WORDS,
)
def get_iaq_baseline(self):
""" Retreives the IAQ algorithm baseline for CO2eq and TVOC """
return self._i2c_read_words_from_cmd(
SGP30_CMD_GET_IAQ_BASELINE_HEX,
SGP30_CMD_GET_IAQ_BASELINE_MAX_MS,
SGP30_CMD_GET_IAQ_BASELINE_WORDS,
)
def set_iaq_baseline(self, co2eq, tvoc):
""" Sets the previously recorded IAQ algorithm baseline for CO2eq and TVOC """
if co2eq == 0 and tvoc == 0:
raise ValueError("Invalid baseline values used")
buffer = []
for value in [tvoc, co2eq]:
arr = [value >> 8, value & 0xFF]
arr.append(generate_crc(arr))
buffer += arr
self._i2c_read_words_from_cmd(
SGP30_CMD_SET_IAQ_BASELINE_HEX + buffer,
SGP30_CMD_SET_IAQ_BASELINE_MAX_MS,
SGP30_CMD_SET_IAQ_BASELINE_WORDS,
)
def set_absolute_humidity(self, absolute_humidity):
""" Sets absolute humidity compensation. To disable,
set 0. """
buffer = []
arr = [absolute_humidity >> 8, absolute_humidity & 0xFF]
arr.append(generate_crc(arr))
buffer += arr
self._i2c_read_words_from_cmd(
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_HEX + buffer,
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_MAX_MS,
SGP30_CMD_SET_ABSOLUTE_HUMIDITY_WORDS,
)
def measure_test(self):
""" Runs on-chip self test """
return self._i2c_read_words_from_cmd(
SGP30_CMD_MEASURE_TEST_HEX,
SGP30_CMD_MEASURE_TEST_MAX_MS,
SGP30_CMD_MEASURE_TEST_WORDS,
)[0]
def get_feature_set(self):
""" Retrieves feature set of sensor """
return self._i2c_read_words_from_cmd(
SGP30_CMD_GET_FEATURE_SET_HEX,
SGP30_CMD_GET_FEATURE_SET_MAX_MS,
SGP30_CMD_GET_FEATURE_SET_WORDS,
)[0]
def measure_raw(self):
""" Returns raw H2 and Ethanol signals, used for part verification and testing """
return self._i2c_read_words_from_cmd(
SGP30_CMD_MEASURE_RAW_HEX,
SGP30_CMD_MEASURE_RAW_MAX_MS,
SGP30_CMD_MEASURE_RAW_WORDS,
)
# TODO: Get TVOC inceptive baseline
# TODO: Set TVOC baseline
# TODO: Soft Reset (datasheet section 6.4)
def get_serial(self):
""" Retrieves sensor serial """
serial = self.serial = self._i2c_read_words_from_cmd(
SGP30_CMD_GET_SERIAL_ID_HEX,
SGP30_CMD_GET_SERIAL_ID_MAX_MS,
SGP30_CMD_GET_SERIAL_ID_WORDS,
)
return hex(int.from_bytes(bytearray(serial), "large"))
@property
def co2eq(self):
""" Carbon Dioxide Equivalent in parts per million (ppm) """
return self.measure_iaq()[0]
@property
def baseline_co2eq(self):
""" Carbon Dioxide Equivalent baseline value """
return self.get_iaq_baseline()[0]
@property
def tvoc(self):
""" Total Volatile Organic Compound in parts per billion (ppb) """
return self.measure_iaq()[1]
@property
def baseline_tvoc(self):
""" Total Volatile Organic Compound baseline value """
return self.get_iaq_baseline()[1]
@property
def raw_h2(self):
""" Raw H2 signal """
return self.measure_raw()[0]
@property
def raw_ethanol(self):
""" Raw Ethanol signal """
return self.measure_raw()[1]
def _i2c_read_words_from_cmd(self, command, delay, reply_size):
""" Runs an SGP command query, gets a reply and CRC results if necessary """
self._i2c.writeto(self.addr, bytes(command))
sleep_ms(delay)
if not reply_size:
return None
crc_result = bytearray(reply_size * (SGP30_WORD_LEN + 1))
self._i2c.readfrom_into(self.addr, crc_result)
result = []
for i in range(reply_size):
word = [crc_result[3 * i], crc_result[3 * i + 1]]
crc = crc_result[3 * i + 2]
if generate_crc(word) != crc:
raise RuntimeError("CRC Error")
result.append(word[0] << 8 | word[1])
return result
def generate_crc(data):
""" 8-bit CRC algorithm for checking data.
Calculation described in section 6.6 of SGP30 datasheet """
crc = SGP30_CRC8_INIT
# Calculates 8-Bit CRC checksum with given polynomial
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x80:
crc = (crc << 1) ^ SGP30_CRC8_POLYNOMIAL
else:
crc <<= 1
return crc & 0xFF
def convert_r_to_a_humidity(temp_c, r_humidity_perc, fixed_point=True):
""" Converts relative to absolute humidity as per the equation
found in datasheet """
a_humidity_gm3 = 216.7 * (
(r_humidity_perc / 100 * 6.112 * exp(17.62 * temp_c / (243.12 + temp_c)))
/ (273.15 + temp_c)
)
# Return in 8.8 bit fixed point format (for setting humidity compensation), if not
# simply return the calculated value in g/m^3
if fixed_point:
a_humidity_gm3 = (int(a_humidity_gm3) << 8) + (int(a_humidity_gm3 % 1 * 256))
return a_humidity_gm3

View File

@ -0,0 +1,135 @@
from machine import I2C
import time
_I2CADDR = const(0x3E)
# commands
_LCD_CLEARDISPLAY = const(0x01)
_LCD_RETURNHOME = const(0x02)
_LCD_ENTRYMODESET = const(0x04)
_LCD_DISPLAYCONTROL = const(0x08)
_LCD_CURSORSHIFT = const(0x10)
_LCD_FUNCTIONSET = const(0x20)
_LCD_SETCGRAMADDR = const(0x40)
_LCD_SETDDRAMADDR = const(0x80)
# flags for display entry mode
_LCD_ENTRYRIGHT = const(0x00)
_LCD_ENTRYLEFT = const(0x02)
_LCD_ENTRYSHIFTINCREMENT = const(0x01)
_LCD_ENTRYSHIFTDECREMENT = const(0x00)
# flags for display on/off control
_LCD_DISPLAYON = const(0x04)
_LCD_DISPLAYOFF = const(0x00)
_LCD_CURSORON = const(0x02)
_LCD_CURSOROFF = const(0x00)
_LCD_BLINKON = const(0x01)
_LCD_BLINKOFF = const(0x00)
# flags for display/cursor shift
_LCD_DISPLAYMOVE = const(0x08)
_LCD_CURSORMOVE = const(0x00)
_LCD_MOVERIGHT = const(0x04)
_LCD_MOVELEFT = const(0x00)
# flags for function set
_LCD_8BITMODE = const(0x10)
_LCD_4BITMODE = const(0x00)
_LCD_2LINE = const(0x08)
_LCD_1LINE = const(0x00)
_LCD_5x10DOTS = const(0x04)
_LCD_5x8DOTS = const(0x00)
class lcd:
def __init__(self, i2c, address = _I2CADDR, oneline = False, charsize = _LCD_5x8DOTS):
self.i2c = i2c
self.i2c.scan()
self.address = address
self.disp_func = _LCD_DISPLAYON
if not oneline:
self.disp_func |= _LCD_2LINE
elif charsize != 0:
# for 1-line displays you can choose another dotsize
self.disp_func |= _LCD_5x10DOTS
# wait for display init after power-on
time.sleep_ms(50) # 50ms
# send function set
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(200) #time.sleep(0.000150) # 150µs = 0.15ms
self.cmd(_LCD_FUNCTIONSET | self.disp_func)
time.sleep_us(5000) #time.sleep(0.0045) # 4.5ms
# turn on the display
self.disp_ctrl = _LCD_DISPLAYON | _LCD_CURSOROFF | _LCD_BLINKOFF
self.display(True)
# clear it
self.clear()
# set default text direction (left-to-right)
self.disp_mode = _LCD_ENTRYLEFT | _LCD_ENTRYSHIFTDECREMENT
self.cmd(_LCD_ENTRYMODESET | self.disp_mode)
def cmd(self, command):
assert command >= 0 and command < 256
command = bytearray([command])
self.i2c.writeto_mem(self.address, 0x80, command)
def write_char(self, c):
assert c >= 0 and c < 256
c = bytearray([c])
self.i2c.writeto_mem(self.address, 0x40, c)
def write(self, text):
for char in text:
self.write_char(ord(char))
def cursor(self, state):
if state:
self.disp_ctrl |= _LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_CURSORON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def setCursor(self, col, row):
col = (col | 0x80) if row == 0 else (col | 0xc0)
self.cmd(col)
def autoscroll(self, state):
if state:
self.disp_ctrl |= _LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_ENTRYSHIFTINCREMENT
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def blink(self, state):
if state:
self.disp_ctrl |= _LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_BLINKON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def display(self, state):
if state:
self.disp_ctrl |= _LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
else:
self.disp_ctrl &= ~_LCD_DISPLAYON
self.cmd(_LCD_DISPLAYCONTROL | self.disp_ctrl)
def clear(self):
self.cmd(_LCD_CLEARDISPLAY)
time.sleep_ms(2) # 2ms
def home(self):
self.cmd(_LCD_RETURNHOME)
time.sleep_ms(2) # 2m

Some files were not shown because too many files have changed in this diff Show More