Compare commits
13 Commits
dcbf8d6b8c
...
8b88aa1a69
| Author | SHA1 | Date |
|---|---|---|
|
|
8b88aa1a69 | |
|
|
dfe9abc3cc | |
|
|
b4c405ccbb | |
|
|
c701cd00bd | |
|
|
e3aa121024 | |
|
|
4cb65f7d7b | |
|
|
2b56e23b9a | |
|
|
78bb708119 | |
|
|
85e2fffb7f | |
|
|
4c11796157 | |
|
|
c2249db282 | |
|
|
28b15337e0 | |
|
|
07d5c67afb |
|
|
@ -0,0 +1,259 @@
|
|||
# Authors: Paul Cunnane 2016, Peter Dahlebrg 2016
|
||||
#
|
||||
# This module borrows from the Adafruit BME280 Python library. Original
|
||||
# Copyright notices are reproduced below.
|
||||
#
|
||||
# Those libraries were written for the Raspberry Pi. This modification is
|
||||
# intended for the MicroPython and esp8266 boards.
|
||||
#
|
||||
# Copyright (c) 2014 Adafruit Industries
|
||||
# Author: Tony DiCola
|
||||
#
|
||||
# Based on the BMP280 driver with BME280 changes provided by
|
||||
# David J Taylor, Edinburgh (www.satsignal.eu)
|
||||
#
|
||||
# Based on Adafruit_I2C.py created by Kevin Townsend.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import time
|
||||
from ustruct import unpack, unpack_from
|
||||
from array import array
|
||||
|
||||
# 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_REGISTER_CONTROL_HUM = 0xF2
|
||||
BME280_REGISTER_CONTROL = 0xF4
|
||||
|
||||
|
||||
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
|
||||
self.address = address
|
||||
if i2c is None:
|
||||
raise ValueError('An I2C object is required.')
|
||||
self.i2c = i2c
|
||||
|
||||
# load calibration data
|
||||
dig_88_a1 = self.i2c.readfrom_mem(self.address, 0x88, 26)
|
||||
dig_e1_e7 = self.i2c.readfrom_mem(self.address, 0xE1, 7)
|
||||
self.dig_T1, self.dig_T2, self.dig_T3, self.dig_P1, \
|
||||
self.dig_P2, self.dig_P3, self.dig_P4, self.dig_P5, \
|
||||
self.dig_P6, self.dig_P7, self.dig_P8, self.dig_P9, \
|
||||
_, self.dig_H1 = unpack("<HhhHhhhhhhhhBB", dig_88_a1)
|
||||
|
||||
self.dig_H2, self.dig_H3 = unpack("<hB", dig_e1_e7)
|
||||
e4_sign = unpack_from("<b", dig_e1_e7, 3)[0]
|
||||
self.dig_H4 = (e4_sign << 4) | (dig_e1_e7[4] & 0xF)
|
||||
|
||||
e6_sign = unpack_from("<b", dig_e1_e7, 5)[0]
|
||||
self.dig_H5 = (e6_sign << 4) | (dig_e1_e7[4] >> 4)
|
||||
|
||||
self.dig_H6 = unpack_from("<b", dig_e1_e7, 6)[0]
|
||||
|
||||
self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
|
||||
bytearray([0x3F]))
|
||||
self.t_fine = 0
|
||||
|
||||
# temporary data holders which stay allocated
|
||||
self._l1_barray = bytearray(1)
|
||||
self._l8_barray = bytearray(8)
|
||||
self._l3_resultarray = array("i", [0, 0, 0])
|
||||
|
||||
def read_raw_data(self, result):
|
||||
""" Reads the raw (uncompensated) data from the sensor.
|
||||
|
||||
Args:
|
||||
result: array of length 3 or alike where the result will be
|
||||
stored, in temperature, pressure, humidity order
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
self._l1_barray[0] = self._mode
|
||||
self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL_HUM,
|
||||
self._l1_barray)
|
||||
self._l1_barray[0] = self._mode << 5 | self._mode << 2 | 1
|
||||
self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
|
||||
self._l1_barray)
|
||||
|
||||
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
|
||||
|
||||
# burst readout from 0xF7 to 0xFE, recommended by datasheet
|
||||
self.i2c.readfrom_mem_into(self.address, 0xF7, self._l8_barray)
|
||||
readout = self._l8_barray
|
||||
# pressure(0xF7): ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
raw_press = ((readout[0] << 16) | (readout[1] << 8) | readout[2]) >> 4
|
||||
# temperature(0xFA): ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
raw_temp = ((readout[3] << 16) | (readout[4] << 8) | readout[5]) >> 4
|
||||
# humidity(0xFD): (msb << 8) | lsb
|
||||
raw_hum = (readout[6] << 8) | readout[7]
|
||||
|
||||
result[0] = raw_temp
|
||||
result[1] = raw_press
|
||||
result[2] = raw_hum
|
||||
|
||||
def read_compensated_data(self, result=None):
|
||||
""" Reads the data from the sensor and returns the compensated data.
|
||||
|
||||
Args:
|
||||
result: array of length 3 or alike where the result will be
|
||||
stored, in temperature, pressure, humidity order. You may use
|
||||
this to read out the sensor without allocating heap memory
|
||||
|
||||
Returns:
|
||||
array with temperature, pressure, humidity. Will be the one from
|
||||
the result parameter if not None
|
||||
"""
|
||||
self.read_raw_data(self._l3_resultarray)
|
||||
raw_temp, raw_press, raw_hum = self._l3_resultarray
|
||||
# temperature
|
||||
var1 = ((raw_temp >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
|
||||
var2 = (((((raw_temp >> 4) - self.dig_T1) *
|
||||
((raw_temp >> 4) - self.dig_T1)) >> 12) * self.dig_T3) >> 14
|
||||
self.t_fine = var1 + var2
|
||||
temp = (self.t_fine * 5 + 128) >> 8
|
||||
|
||||
# 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:
|
||||
pressure = 0
|
||||
else:
|
||||
p = 1048576 - raw_press
|
||||
p = (((p << 31) - var2) * 3125) // var1
|
||||
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
|
||||
var2 = (self.dig_P8 * p) >> 19
|
||||
pressure = ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
|
||||
|
||||
# humidity
|
||||
h = self.t_fine - 76800
|
||||
h = (((((raw_hum << 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
|
||||
humidity = h >> 12
|
||||
|
||||
if result:
|
||||
result[0] = temp
|
||||
result[1] = pressure
|
||||
result[2] = humidity
|
||||
return result
|
||||
|
||||
return array("i", (temp, pressure, humidity))
|
||||
|
||||
@property
|
||||
def values(self):
|
||||
""" human readable values """
|
||||
|
||||
t, p, h = self.read_compensated_data()
|
||||
|
||||
p = p // 256
|
||||
pi = p // 100
|
||||
pd = p - pi * 100
|
||||
|
||||
hi = h // 1024
|
||||
hd = h * 100 // 1024 - hi * 100
|
||||
return ("{}C".format(t / 100), "{}.{:02d}hPa".format(pi, pd),
|
||||
"{}.{:02d}%".format(hi, hd))
|
||||
|
||||
|
||||
# ==================================================================
|
||||
# BME280 readings can be executed in thread:
|
||||
|
||||
'''
|
||||
import machine, _thread, time
|
||||
import micropython, gc
|
||||
import bme280
|
||||
|
||||
i2c=machine.I2C(scl=machine.Pin(26),sda=machine.Pin(25),speed=400000)
|
||||
bme=bme280.BME280(i2c=i2c)
|
||||
|
||||
def bmevalues():
|
||||
t, p, h = bme.read_compensated_data()
|
||||
|
||||
p = p // 256
|
||||
pi = p // 100
|
||||
pd = p - pi * 100
|
||||
|
||||
hi = h // 1024
|
||||
hd = h * 100 // 1024 - hi * 100
|
||||
#return "[{}] T={0:1g}C ".format(time.strftime("%H:%M:%S",time.localtime()), round(t / 100,1)) + "P={}.{:02d}hPa ".format(pi, pd) + "H={}.{:01d}%".format(hi, hd)
|
||||
return "[{}] T={}C ".format(time.strftime("%H:%M:%S",time.localtime()), t / 100) + "P={}.{:02d}hPa ".format(pi, pd) + "H={}.{:02d}%".format(hi, hd)
|
||||
|
||||
|
||||
def bmerun(interval=60):
|
||||
_thread.allowsuspend(True)
|
||||
sendmsg = True
|
||||
send_time = time.time() + interval
|
||||
while True:
|
||||
while time.time() < send_time:
|
||||
notif = _thread.getnotification()
|
||||
if notif == 10002:
|
||||
_thread.sendmsg(_thread.getReplID(), bmevalues())
|
||||
elif notif == 10004:
|
||||
sendmsg = False
|
||||
elif notif == 10006:
|
||||
sendmsg = True
|
||||
elif (notif <= 3600) and (notif >= 10):
|
||||
interval = notif
|
||||
send_time = time.time() + interval
|
||||
_thread.sendmsg(_thread.getReplID(), "Interval set to {} seconds".format(interval))
|
||||
|
||||
time.sleep_ms(100)
|
||||
send_time = send_time + interval
|
||||
if sendmsg:
|
||||
_thread.sendmsg(_thread.getReplID(), bmevalues())
|
||||
|
||||
_thread.stack_size(3*1024)
|
||||
bmeth=_thread.start_new_thread("BME280", bmerun, (60,))
|
||||
|
||||
'''
|
||||
|
After Width: | Height: | Size: 156 KiB |
|
|
@ -0,0 +1,259 @@
|
|||
# Authors: Paul Cunnane 2016, Peter Dahlebrg 2016
|
||||
#
|
||||
# This module borrows from the Adafruit BME280 Python library. Original
|
||||
# Copyright notices are reproduced below.
|
||||
#
|
||||
# Those libraries were written for the Raspberry Pi. This modification is
|
||||
# intended for the MicroPython and esp8266 boards.
|
||||
#
|
||||
# Copyright (c) 2014 Adafruit Industries
|
||||
# Author: Tony DiCola
|
||||
#
|
||||
# Based on the BMP280 driver with BME280 changes provided by
|
||||
# David J Taylor, Edinburgh (www.satsignal.eu)
|
||||
#
|
||||
# Based on Adafruit_I2C.py created by Kevin Townsend.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import time
|
||||
from ustruct import unpack, unpack_from
|
||||
from array import array
|
||||
|
||||
# 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_REGISTER_CONTROL_HUM = 0xF2
|
||||
BME280_REGISTER_CONTROL = 0xF4
|
||||
|
||||
|
||||
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
|
||||
self.address = address
|
||||
if i2c is None:
|
||||
raise ValueError('An I2C object is required.')
|
||||
self.i2c = i2c
|
||||
|
||||
# load calibration data
|
||||
dig_88_a1 = self.i2c.readfrom_mem(self.address, 0x88, 26)
|
||||
dig_e1_e7 = self.i2c.readfrom_mem(self.address, 0xE1, 7)
|
||||
self.dig_T1, self.dig_T2, self.dig_T3, self.dig_P1, \
|
||||
self.dig_P2, self.dig_P3, self.dig_P4, self.dig_P5, \
|
||||
self.dig_P6, self.dig_P7, self.dig_P8, self.dig_P9, \
|
||||
_, self.dig_H1 = unpack("<HhhHhhhhhhhhBB", dig_88_a1)
|
||||
|
||||
self.dig_H2, self.dig_H3 = unpack("<hB", dig_e1_e7)
|
||||
e4_sign = unpack_from("<b", dig_e1_e7, 3)[0]
|
||||
self.dig_H4 = (e4_sign << 4) | (dig_e1_e7[4] & 0xF)
|
||||
|
||||
e6_sign = unpack_from("<b", dig_e1_e7, 5)[0]
|
||||
self.dig_H5 = (e6_sign << 4) | (dig_e1_e7[4] >> 4)
|
||||
|
||||
self.dig_H6 = unpack_from("<b", dig_e1_e7, 6)[0]
|
||||
|
||||
self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
|
||||
bytearray([0x3F]))
|
||||
self.t_fine = 0
|
||||
|
||||
# temporary data holders which stay allocated
|
||||
self._l1_barray = bytearray(1)
|
||||
self._l8_barray = bytearray(8)
|
||||
self._l3_resultarray = array("i", [0, 0, 0])
|
||||
|
||||
def read_raw_data(self, result):
|
||||
""" Reads the raw (uncompensated) data from the sensor.
|
||||
|
||||
Args:
|
||||
result: array of length 3 or alike where the result will be
|
||||
stored, in temperature, pressure, humidity order
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
|
||||
self._l1_barray[0] = self._mode
|
||||
self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL_HUM,
|
||||
self._l1_barray)
|
||||
self._l1_barray[0] = self._mode << 5 | self._mode << 2 | 1
|
||||
self.i2c.writeto_mem(self.address, BME280_REGISTER_CONTROL,
|
||||
self._l1_barray)
|
||||
|
||||
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
|
||||
|
||||
# burst readout from 0xF7 to 0xFE, recommended by datasheet
|
||||
self.i2c.readfrom_mem_into(self.address, 0xF7, self._l8_barray)
|
||||
readout = self._l8_barray
|
||||
# pressure(0xF7): ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
raw_press = ((readout[0] << 16) | (readout[1] << 8) | readout[2]) >> 4
|
||||
# temperature(0xFA): ((msb << 16) | (lsb << 8) | xlsb) >> 4
|
||||
raw_temp = ((readout[3] << 16) | (readout[4] << 8) | readout[5]) >> 4
|
||||
# humidity(0xFD): (msb << 8) | lsb
|
||||
raw_hum = (readout[6] << 8) | readout[7]
|
||||
|
||||
result[0] = raw_temp
|
||||
result[1] = raw_press
|
||||
result[2] = raw_hum
|
||||
|
||||
def read_compensated_data(self, result=None):
|
||||
""" Reads the data from the sensor and returns the compensated data.
|
||||
|
||||
Args:
|
||||
result: array of length 3 or alike where the result will be
|
||||
stored, in temperature, pressure, humidity order. You may use
|
||||
this to read out the sensor without allocating heap memory
|
||||
|
||||
Returns:
|
||||
array with temperature, pressure, humidity. Will be the one from
|
||||
the result parameter if not None
|
||||
"""
|
||||
self.read_raw_data(self._l3_resultarray)
|
||||
raw_temp, raw_press, raw_hum = self._l3_resultarray
|
||||
# temperature
|
||||
var1 = ((raw_temp >> 3) - (self.dig_T1 << 1)) * (self.dig_T2 >> 11)
|
||||
var2 = (((((raw_temp >> 4) - self.dig_T1) *
|
||||
((raw_temp >> 4) - self.dig_T1)) >> 12) * self.dig_T3) >> 14
|
||||
self.t_fine = var1 + var2
|
||||
temp = (self.t_fine * 5 + 128) >> 8
|
||||
|
||||
# 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:
|
||||
pressure = 0
|
||||
else:
|
||||
p = 1048576 - raw_press
|
||||
p = (((p << 31) - var2) * 3125) // var1
|
||||
var1 = (self.dig_P9 * (p >> 13) * (p >> 13)) >> 25
|
||||
var2 = (self.dig_P8 * p) >> 19
|
||||
pressure = ((p + var1 + var2) >> 8) + (self.dig_P7 << 4)
|
||||
|
||||
# humidity
|
||||
h = self.t_fine - 76800
|
||||
h = (((((raw_hum << 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
|
||||
humidity = h >> 12
|
||||
|
||||
if result:
|
||||
result[0] = temp
|
||||
result[1] = pressure
|
||||
result[2] = humidity
|
||||
return result
|
||||
|
||||
return array("i", (temp, pressure, humidity))
|
||||
|
||||
@property
|
||||
def values(self):
|
||||
""" human readable values """
|
||||
|
||||
t, p, h = self.read_compensated_data()
|
||||
|
||||
p = p // 256
|
||||
pi = p // 100
|
||||
pd = p - pi * 100
|
||||
|
||||
hi = h // 1024
|
||||
hd = h * 100 // 1024 - hi * 100
|
||||
return ("{}C".format(t / 100), "{}.{:02d}hPa".format(pi, pd),
|
||||
"{}.{:02d}%".format(hi, hd))
|
||||
|
||||
|
||||
# ==================================================================
|
||||
# BME280 readings can be executed in thread:
|
||||
|
||||
'''
|
||||
import machine, _thread, time
|
||||
import micropython, gc
|
||||
import bme280
|
||||
|
||||
i2c=machine.I2C(scl=machine.Pin(26),sda=machine.Pin(25),speed=400000)
|
||||
bme=bme280.BME280(i2c=i2c)
|
||||
|
||||
def bmevalues():
|
||||
t, p, h = bme.read_compensated_data()
|
||||
|
||||
p = p // 256
|
||||
pi = p // 100
|
||||
pd = p - pi * 100
|
||||
|
||||
hi = h // 1024
|
||||
hd = h * 100 // 1024 - hi * 100
|
||||
#return "[{}] T={0:1g}C ".format(time.strftime("%H:%M:%S",time.localtime()), round(t / 100,1)) + "P={}.{:02d}hPa ".format(pi, pd) + "H={}.{:01d}%".format(hi, hd)
|
||||
return "[{}] T={}C ".format(time.strftime("%H:%M:%S",time.localtime()), t / 100) + "P={}.{:02d}hPa ".format(pi, pd) + "H={}.{:02d}%".format(hi, hd)
|
||||
|
||||
|
||||
def bmerun(interval=60):
|
||||
_thread.allowsuspend(True)
|
||||
sendmsg = True
|
||||
send_time = time.time() + interval
|
||||
while True:
|
||||
while time.time() < send_time:
|
||||
notif = _thread.getnotification()
|
||||
if notif == 10002:
|
||||
_thread.sendmsg(_thread.getReplID(), bmevalues())
|
||||
elif notif == 10004:
|
||||
sendmsg = False
|
||||
elif notif == 10006:
|
||||
sendmsg = True
|
||||
elif (notif <= 3600) and (notif >= 10):
|
||||
interval = notif
|
||||
send_time = time.time() + interval
|
||||
_thread.sendmsg(_thread.getReplID(), "Interval set to {} seconds".format(interval))
|
||||
|
||||
time.sleep_ms(100)
|
||||
send_time = send_time + interval
|
||||
if sendmsg:
|
||||
_thread.sendmsg(_thread.getReplID(), bmevalues())
|
||||
|
||||
_thread.stack_size(3*1024)
|
||||
bmeth=_thread.start_new_thread("BME280", bmerun, (60,))
|
||||
|
||||
'''
|
||||
|
After Width: | Height: | Size: 106 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
|
@ -0,0 +1,37 @@
|
|||
version: "3"
|
||||
services:
|
||||
influxdb:
|
||||
image: influxdb:1.7-alpine
|
||||
restart: on-failure:5
|
||||
networks:
|
||||
- traefik_net
|
||||
volumes:
|
||||
- ./data/influx:/var/lib/influxdb/
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_net"
|
||||
- "traefik.http.frontend.rule=Host:iot-db.uni.clkl.de"
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:5.4.3
|
||||
volumes:
|
||||
- "./data/grafana/:/var/lib/grafana/"
|
||||
environment:
|
||||
- "GF_SECURITY_ADMIN_USER=admin"
|
||||
- "GF_SECURITY_ADMIN_PASSWORD=secret"
|
||||
restart: on-failure:5
|
||||
networks:
|
||||
- traefik_net
|
||||
- default
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_net"
|
||||
- "traefik.http.frontend.rule=Host:iot.uni.clkl.de"
|
||||
|
||||
|
||||
networks:
|
||||
traefik_net:
|
||||
external:
|
||||
name: traefik_net
|
||||
|
||||
# initialize DB: requests.post("http://iot-db.uni.clkl.de/query?q=CREATE DATABASE ids"
|
||||
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 59 KiB |
|
After Width: | Height: | Size: 598 KiB |
|
|
@ -0,0 +1,315 @@
|
|||
%Berkeley / Goettingen / Hannover / Marburg / PaloAlto / Rochester
|
||||
\usetheme[hideothersubsections]{Goettingen}
|
||||
|
||||
\RequirePackage{pgf}
|
||||
\RequirePackage{tikz}
|
||||
\RequirePackage{pdfrender}
|
||||
|
||||
\tikzset{
|
||||
rectangle with rounded corners north west/.initial=4pt,
|
||||
rectangle with rounded corners south west/.initial=4pt,
|
||||
rectangle with rounded corners north east/.initial=4pt,
|
||||
rectangle with rounded corners south east/.initial=4pt,
|
||||
}
|
||||
%\makeatletter
|
||||
\pgfdeclareshape{rectangle with rounded corners}{
|
||||
\inheritanchorborder[from=rectangle]
|
||||
\savedmacro{\neoffset}{
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners north east}{\pgf@rectc}
|
||||
\let\neoffset\pgf@rectc
|
||||
}
|
||||
\savedmacro{\nwoffset}{
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners north west}{\pgf@rectc}
|
||||
\let\nwoffset\pgf@rectc
|
||||
}
|
||||
\savedmacro{\seoffset}{
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners south east}{\pgf@rectc}
|
||||
\let\seoffset\pgf@rectc
|
||||
}
|
||||
\savedmacro{\swoffset}{
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners south west}{\pgf@rectc}
|
||||
\let\swoffset\pgf@rectc
|
||||
}
|
||||
\savedanchor{\north}{
|
||||
\pgf@y=.5\ht\pgfnodeparttextbox
|
||||
\pgf@x=0pt
|
||||
\setlength{\pgf@ya}{\pgfshapeminheight}
|
||||
\ifdim\pgf@y<.5\pgf@ya
|
||||
\pgf@y=.5\pgf@ya
|
||||
\fi
|
||||
}
|
||||
\savedanchor{\south}{
|
||||
\pgf@y=-.5\ht\pgfnodeparttextbox
|
||||
\pgf@x=0pt
|
||||
\setlength{\pgf@ya}{\pgfshapeminheight}
|
||||
\ifdim\pgf@y>-.5\pgf@ya
|
||||
\pgf@y=-.5\pgf@ya
|
||||
\fi
|
||||
}
|
||||
\savedanchor{\east}{
|
||||
\pgf@y=0pt
|
||||
\pgf@x=.5\wd\pgfnodeparttextbox
|
||||
\addtolength{\pgf@x}{2ex}
|
||||
\setlength{\pgf@xa}{\pgfshapeminwidth}
|
||||
\ifdim\pgf@x<.5\pgf@xa
|
||||
\pgf@x=.5\pgf@xa
|
||||
\fi
|
||||
}
|
||||
\savedanchor{\west}{
|
||||
\pgf@y=0pt
|
||||
\pgf@x=-.5\wd\pgfnodeparttextbox
|
||||
\addtolength{\pgf@x}{-2ex}
|
||||
\setlength{\pgf@xa}{\pgfshapeminwidth}
|
||||
\ifdim\pgf@x>-.5\pgf@xa
|
||||
\pgf@x=-.5\pgf@xa
|
||||
\fi
|
||||
}
|
||||
\savedanchor{\northeast}{
|
||||
\pgf@y=.5\ht\pgfnodeparttextbox % height of the box
|
||||
\pgf@x=.5\wd\pgfnodeparttextbox % width of the box
|
||||
\addtolength{\pgf@x}{2ex}
|
||||
\setlength{\pgf@xa}{\pgfshapeminwidth}
|
||||
\ifdim\pgf@x<.5\pgf@xa
|
||||
\pgf@x=.5\pgf@xa
|
||||
\fi
|
||||
\setlength{\pgf@ya}{\pgfshapeminheight}
|
||||
\ifdim\pgf@y<.5\pgf@ya
|
||||
\pgf@y=.5\pgf@ya
|
||||
\fi
|
||||
}
|
||||
\savedanchor{\southwest}{
|
||||
\pgf@y=-.5\ht\pgfnodeparttextbox
|
||||
\pgf@x=-.5\wd\pgfnodeparttextbox
|
||||
\addtolength{\pgf@x}{-2ex}
|
||||
% \pgf@x=0pt
|
||||
\setlength{\pgf@xa}{\pgfshapeminwidth}
|
||||
\ifdim\pgf@x>-.5\pgf@xa
|
||||
\pgf@x=-.5\pgf@xa
|
||||
\fi
|
||||
\setlength{\pgf@ya}{\pgfshapeminheight}
|
||||
\ifdim\pgf@y>-.5\pgf@ya
|
||||
\pgf@y=-.5\pgf@ya
|
||||
\fi
|
||||
}
|
||||
\anchor{text}{%
|
||||
\northeast%
|
||||
\pgf@x=-.5\wd\pgfnodeparttextbox%
|
||||
\pgfmathsetlength{\pgf@y}{-.5ex}
|
||||
}
|
||||
\anchor{north east}{
|
||||
\northeast
|
||||
\pgfmathsetmacro{\nw}{(1-sin(45))*\neoffset}
|
||||
\addtolength{\pgf@x}{-\nw pt}
|
||||
\addtolength{\pgf@y}{-\nw pt}
|
||||
}
|
||||
\anchor{center}{
|
||||
\pgf@x=0pt
|
||||
\pgf@y=0pt
|
||||
}
|
||||
\anchor{south west}{
|
||||
\southwest
|
||||
\pgfmathsetmacro{\nw}{(1-sin(45))*\swoffset}
|
||||
\addtolength{\pgf@x}{\nw pt}
|
||||
\addtolength{\pgf@y}{\nw pt}
|
||||
}
|
||||
\anchor{north west}{
|
||||
\northeast
|
||||
\pgfmathsetmacro{\temp@x}{\pgf@x}
|
||||
\southwest
|
||||
\pgfmathsetmacro{\temp@xtwo}{\pgf@x}
|
||||
\northeast
|
||||
\pgfmathsetmacro{\xdiff}{\temp@x-\temp@xtwo}
|
||||
\def\pgf@xa{\pgf@x-\xdiff}
|
||||
\
|
||||
\pgfmathsetmacro{\nw}{(1-sin(45))*\nwoffset}
|
||||
\def\pgf@xaa{\pgf@xa+\nw}
|
||||
\def\pgf@yaa{\pgf@y-\nw}
|
||||
\pgfpoint{\pgf@xaa}{\pgf@yaa}
|
||||
}
|
||||
\anchor{south east}{
|
||||
\southwest
|
||||
\pgfmathsetmacro{\temp@x}{\pgf@x}
|
||||
\northeast
|
||||
\pgfmathsetmacro{\temp@xtwo}{\pgf@x}
|
||||
\southwest
|
||||
\pgfmathsetmacro{\xdiff}{\temp@x-\temp@xtwo}
|
||||
\def\pgf@xa{\pgf@x-\xdiff}
|
||||
\pgfmathsetmacro{\nw}{(1-sin(45))*\seoffset}
|
||||
\def\pgf@xaa{\pgf@xa-\nw}
|
||||
\def\pgf@yaa{\pgf@y+\nw}
|
||||
\pgfpoint{\pgf@xaa}{\pgf@yaa}
|
||||
}
|
||||
\anchor{south}{\south}
|
||||
\anchor{north}{\north}
|
||||
\anchor{east}{\east}
|
||||
\anchor{west}{\west}
|
||||
\backgroundpath{% this is new
|
||||
% store lower right in xa/ya and upper right in xb/yb
|
||||
\southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
|
||||
\northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
|
||||
% construct main path
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners north west}{\pgf@rectc}
|
||||
\pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
|
||||
\pgfpathmoveto{\pgfpoint{\pgf@xa}{\pgf@ya}}
|
||||
\pgfpathlineto{\pgfpoint{\pgf@xa}{\pgf@yb}}
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners north east}{\pgf@rectc}
|
||||
\pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
|
||||
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@yb}}
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners south east}{\pgf@rectc}
|
||||
\pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
|
||||
\pgfpathlineto{\pgfpoint{\pgf@xb}{\pgf@ya}}
|
||||
\pgfkeysgetvalue{/tikz/rectangle with rounded corners south west}{\pgf@rectc}
|
||||
\pgfsetcornersarced{\pgfpoint{\pgf@rectc}{\pgf@rectc}}
|
||||
\pgfpathclose
|
||||
}
|
||||
}
|
||||
|
||||
\pgfdeclareimage[width=1.4em]{uniheader}{\meta/config/images/logo}
|
||||
\pgfdeclareimage[width=2.8em]{uniheadertitle}{\meta/config/images/logo}
|
||||
\setbeamertemplate{blocks}[shadow=false]
|
||||
\setbeamercovered{transparent}
|
||||
|
||||
\beamer@headheight=0.1\paperheight
|
||||
|
||||
\setbeamercolor*{Title bar}{fg=unibablueI}
|
||||
\setbeamercolor*{Location bar}{fg=unibablueI,bg=white}
|
||||
\setbeamercolor*{frametitle}{parent=Title bar}
|
||||
\setbeamercolor*{block title}{bg=unibablueI,fg=white}
|
||||
\setbeamercolor*{block body}{bg=unibagrayV,fg=black}
|
||||
\setbeamercolor*{block title alerted}{bg=nounibaredII,fg=white}
|
||||
\setbeamercolor*{block body alerted}{bg=unibaredV,fg=black}
|
||||
\setbeamercolor*{block title example}{bg=unibayellowII,fg=black}
|
||||
\setbeamercolor*{block body example}{bg=unibayellowV,fg=black}
|
||||
\setbeamercolor*{normal text}{bg=white,fg=black}
|
||||
\setbeamercolor*{alerted text}{fg=nounibaredII}
|
||||
\setbeamercolor*{section in head/foot}{fg=unibablueI}
|
||||
\setbeamercolor*{item}{fg=unibablueI, bg=unibagrayV}
|
||||
|
||||
\usecolortheme[named=unibablueI]{structure}
|
||||
|
||||
\setbeamerfont{section in head/foot}{size=\tiny,series=\normalfont}
|
||||
\setbeamerfont{frametitle}{size=\large}
|
||||
|
||||
\setbeamertemplate{title page}{
|
||||
\begin{tikzpicture}[remember picture,overlay]
|
||||
\node[
|
||||
anchor=south east,
|
||||
draw=unibablueV,
|
||||
thin,
|
||||
fill=unibablueV,
|
||||
shape=rectangle with rounded corners,
|
||||
minimum height=\paperheight-.2cm, minimum width=\beamer@sidebarwidth-.2cm,
|
||||
rectangle with rounded corners north west=0pt,
|
||||
rectangle with rounded corners south west=0pt,
|
||||
rectangle with rounded corners north east=18pt,
|
||||
rectangle with rounded corners south east=0pt,
|
||||
] at ($(current page.south east)+(-.1,.1)$) (b) {};
|
||||
\draw[anchor=north east] node(logo) at ($(b.north east)+(.15,.15)$) { \pgfuseimage{uniheadertitle} };
|
||||
%\draw[unibablueI] node(uniba) [below of=logo, anchor=center]{\scriptsize\unibastring};
|
||||
\end{tikzpicture}
|
||||
\vskip-0.3\beamer@headheight
|
||||
\begin{beamercolorbox}[sep=8pt]{institute}
|
||||
\usebeamerfont{institute}\insertinstitute
|
||||
\end{beamercolorbox}
|
||||
\vskip2em\par
|
||||
\begin{beamercolorbox}[sep=16pt]{title}
|
||||
\usebeamerfont{title}\inserttitle\par%
|
||||
\ifx\insertsubtitle\@empty%
|
||||
\else%
|
||||
\vskip0.25em%
|
||||
{\usebeamerfont{subtitle}\usebeamercolor[fg]{subtitle}\insertsubtitle\par}%
|
||||
\fi%
|
||||
\end{beamercolorbox}%
|
||||
\vskip1em\par
|
||||
\begin{beamercolorbox}[sep=16pt]{date}
|
||||
\usebeamerfont{date}\insertdate
|
||||
\end{beamercolorbox}\vskip-0.5em
|
||||
\begin{beamercolorbox}[sep=16pt]{author}
|
||||
\usebeamerfont{author}\insertauthor
|
||||
\end{beamercolorbox}
|
||||
\vfill
|
||||
}
|
||||
|
||||
|
||||
\setbeamertemplate{frametitle}
|
||||
{
|
||||
\ifx\insertframesubtitle\empty
|
||||
\vskip+0.1cm
|
||||
\usebeamerfont*{frametitle}\insertframetitle
|
||||
\vskip+0.15cm
|
||||
\else
|
||||
\usebeamerfont*{frametitle}\insertframetitle
|
||||
\vskip+0.1cm
|
||||
\hskip+0.5cm\usebeamerfont*{framesubtitle}\insertframesubtitle
|
||||
\vskip+0.15cm
|
||||
\fi
|
||||
}
|
||||
|
||||
%\setbeamertemplate{headline}
|
||||
%{
|
||||
% \vskip -\beamer@headheight
|
||||
% \linethickness{0pt}
|
||||
% \framelatex{
|
||||
% \begin{beamercolorbox}[wd=\paperwidth,ht=\beamer@headheight]{Title bar}
|
||||
% \usebeamerfont{section in head/foot}
|
||||
% %\insertsectionnavigationhorizontal{0pt}{\hskip0.22cm}{}%
|
||||
% \end{beamercolorbox}}
|
||||
%}
|
||||
|
||||
\setbeamertemplate{footline}
|
||||
{
|
||||
\begin{tikzpicture}[remember picture, overlay]
|
||||
\draw[thick, unibablueI] ($(current page.south west)+(.1,0.37\beamer@headheight)$) -- ($(current page.south east)+(-.1,0.37\beamer@headheight)$);
|
||||
\end{tikzpicture}
|
||||
|
||||
\linethickness{0pt}
|
||||
\framelatex{
|
||||
\begin{beamercolorbox}[leftskip=0.2cm, rightskip=0.2cm, wd=\paperwidth,ht=0.35\beamer@headheight,sep=0.05cm]{Location bar}
|
||||
\usebeamerfont{section in head/foot}%
|
||||
\begin{tikzpicture}[remember picture, overlay]
|
||||
\node[anchor=south west] at ($(current page.south west)+(.1,0)$){\insertshorttitle \ | \insertshortauthor \ | \insertshortinstitute};
|
||||
\node[anchor=south] at (current page.south){\ifgit\gitMarkFormat{\gitMarkPref\,\textbullet{}\,\gitMark}\fi};
|
||||
\node[anchor=south east] at ($(current page.south east)+(-.1,0)$){\insertframenumber/\inserttotalframenumber};
|
||||
\end{tikzpicture}
|
||||
\end{beamercolorbox}}
|
||||
}
|
||||
|
||||
\setbeamertemplate{sidebar canvas \beamer@sidebarside}[vertical shading]
|
||||
[top=white,bottom=white]
|
||||
|
||||
\setbeamertemplate{sidebar \beamer@sidebarside}
|
||||
{
|
||||
\begin{tikzpicture}[remember picture,overlay]
|
||||
\node[
|
||||
anchor=south east,
|
||||
draw=unibablueV,
|
||||
thin,
|
||||
fill=unibablueV,
|
||||
shape=rectangle with rounded corners,
|
||||
minimum height=\paperheight-.2cm, minimum width=\beamer@sidebarwidth-.2cm,
|
||||
rectangle with rounded corners north west=0pt,
|
||||
rectangle with rounded corners south west=0pt,
|
||||
rectangle with rounded corners north east=18pt,
|
||||
rectangle with rounded corners south east=0pt,
|
||||
] at ($(current page.south east)+(-.1,.1)$) (b) {};
|
||||
\draw[anchor=north east] node(logo) at ($(b.north east)+(.15,.15)$) { \pgfuseimage{uniheadertitle} };
|
||||
\end{tikzpicture}
|
||||
\vskip12em%
|
||||
\hskip1em\insertverticalnavigation{\beamer@sidebarwidth}%
|
||||
\vfill
|
||||
\ifx\beamer@sidebarside\beamer@lefttext%
|
||||
\else%
|
||||
\usebeamercolor{normal text}%
|
||||
\llap{\usebeamertemplate***{navigation symbols}\hskip0.1cm}%
|
||||
\vskip2pt%
|
||||
\fi%
|
||||
%
|
||||
|
||||
\ifx\beamer@sidebarside\beamer@lefttext%
|
||||
\defbeamertemplate*{sidebar right}{sidebar theme}
|
||||
{%
|
||||
\vfill%
|
||||
\llap{\usebeamertemplate***{navigation symbols}\hskip0.1cm}%
|
||||
\vskip2pt}
|
||||
\fi
|
||||
}
|
||||
|
|
@ -1,16 +1,16 @@
|
|||
%Meta info
|
||||
%Necessary Information
|
||||
\author[C\&F]{Clemens, Franz}
|
||||
\title{IoT Night}
|
||||
\subtitle{S stands for security}
|
||||
\author[clkl]{Clemens}
|
||||
\title{IoT Night $v1.1$}
|
||||
\subtitle{S stands for security\\C stands for completeness\\V stands for verified contents\\E stands for electrical safety\\F stands for fair working conditions\\U stands for unharmed bits }
|
||||
%The day of the presentation
|
||||
\date{\today}
|
||||
|
||||
%Optional Information
|
||||
\subject{IoT ESP8266}
|
||||
\keywords{iot esp8266}
|
||||
\subject{IoT ESP8266 ESP32}
|
||||
\keywords{iot esp8266 esp32}
|
||||
|
||||
\institute[WIAI]{Fachschaft WIAI}
|
||||
\institute[wiai.de]{Fachschaft WIAI}
|
||||
|
||||
\titlegraphic{\includegraphics[width=13mm,height=13mm]{image/logo}}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
@misc{pinmap,
|
||||
url={https://www.roboburada.com/public/assets/ESP8266/pinmap.png}
|
||||
}
|
||||
@misc{pinmap32,
|
||||
url={https://lastminuteengineers.com/esp32-arduino-ide-tutorial/}
|
||||
}
|
||||
@misc{esp8266,
|
||||
url={http://www.c-sharpcorner.com/article/blinking-led-by-esp-12e-nodemcu-v3-module-using-arduinoide/}
|
||||
}
|
||||
|
|
@ -8,10 +11,14 @@
|
|||
url={https://docs.micropython.org/en/latest/esp8266/esp8266/tutorial/intro.html}
|
||||
}
|
||||
@misc{node-dht,
|
||||
url={https://www.mikrocontroller.net/topic/389850}}
|
||||
url={https://www.losant.com/blog/getting-started-with-the-esp8266-and-dht22-sensor}}
|
||||
@misc{node-led,
|
||||
url={https://www.pinterest.de/pin/658088564269958262/}}
|
||||
@misc{node-button,
|
||||
url={https://alexbloggt.com/esp8266-pushover/}}
|
||||
@misc{mp-interrupt,
|
||||
url={{https://docs.micropython.org/en/latest/esp8266/reference/isr_rules.html}}}
|
||||
@misc{bmemod,
|
||||
url={{https://github.com/loboris/MicroPython_ESP32_psRAM_LoBo/blob/master/MicroPython_BUILD/components/micropython/esp32/modules_examples/bme280.py}}}
|
||||
@misc{espbme,
|
||||
url={{https://randomnerdtutorials.com/esp32-web-server-with-bme280-mini-weather-station/}}}
|
||||
|
After Width: | Height: | Size: 156 KiB |
|
After Width: | Height: | Size: 60 KiB |
|
Before Width: | Height: | Size: 122 KiB After Width: | Height: | Size: 59 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 9.6 KiB |
|
Before Width: | Height: | Size: 53 KiB |
|
|
@ -0,0 +1,11 @@
|
|||
\documentclass[11pt,a4paper]{article}
|
||||
|
||||
\usepackage[top=0cm,bottom=0cm]{geometry}
|
||||
\usepackage{graphicx}
|
||||
|
||||
\begin{document}
|
||||
\noindent
|
||||
\includegraphics[width=.85\textwidth]{images/pinmap}\\
|
||||
\includegraphics[width=.85\textwidth]{images/pinmap}\\
|
||||
\includegraphics[width=.85\textwidth]{images/pinmap}
|
||||
\end{document}
|
||||
|
|
@ -79,27 +79,6 @@ compress
|
|||
|
||||
\newcommand{\icon}[1]{\pgfimage[height=1em]{#1}}
|
||||
|
||||
\section*{}
|
||||
\phantomsection
|
||||
\begin{frame}{First things first}\framesubtitle{Hardwareausgabe}
|
||||
\begin{itemize}
|
||||
\item Verfügbare Sets: 20
|
||||
\item Reserviert: ~19
|
||||
\item Kosten: \EUR{8} pro Set
|
||||
\begin{itemize}
|
||||
\item Bank of WIAI
|
||||
\item \url{https://www.paypal.me/clkl/8}
|
||||
\item Cash
|
||||
\end{itemize}
|
||||
\end{itemize}
|
||||
\begin{figure}[H]
|
||||
%\centering
|
||||
%\flushright
|
||||
\includegraphics[width=.3\textwidth]{qr}
|
||||
\label{img:qr}
|
||||
\end{figure}
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}{Content}
|
||||
\tableofcontents
|
||||
\end{frame}
|
||||
|
|
@ -107,24 +86,36 @@ compress
|
|||
%%%%%%%%%% Content starts here %%%%%%%%%%
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
||||
\section{ESP8266}
|
||||
\section{ESP Microcontroller}
|
||||
\subsection{Hardware}
|
||||
\begin{frame}{ESP8266}
|
||||
\begin{frame}{ESP*}
|
||||
ESP8266
|
||||
\begin{itemize}
|
||||
\item 80 MHz, 64 kB RAM (Code), 96 kB RAM (Daten)
|
||||
\item 4 MB Flashspeicher
|
||||
\item 4 MB Flashspeicher (extern)
|
||||
\item Ardunio-kompatibel
|
||||
\item Open Source Hardware
|
||||
\item Billige China-Klone :)
|
||||
\item Wlan
|
||||
\end{itemize}
|
||||
ESP32
|
||||
\begin{itemize}
|
||||
\item 160/240 MHz, 520 kB RAM (Daten)
|
||||
\item Dualcore!
|
||||
\item 4 MB Flashspeicher (extern)
|
||||
\item Ardunio-kompatibel
|
||||
\item Open Source Hardware
|
||||
\item Wlan, Bluetooth 4.2, BLE, Ethernet (Treiber)
|
||||
\end{itemize}
|
||||
\image{.6\textwidth}{esp8266}{ESP8266 + NodeMCU v3 \cite{esp8266}}{img:esp}
|
||||
\end{frame}
|
||||
\begin{frame}{ESP8266 - Pins}
|
||||
\image{.6\textwidth}{pinmap}{ESP8266 Pins \cite{pinmap}}{img:pins}
|
||||
\end{frame}
|
||||
\begin{frame}{ESP32 - Pins}
|
||||
\image{\textwidth}{ESP32-Development-Board-Pinout}{ESP32 Pins \cite{pinmap32}}{img:pins}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Software}
|
||||
\begin{frame}{ESP8266}
|
||||
\begin{frame}{Programmierung}
|
||||
\href{http://nodemcu.com/index_en.html}{NodeMCU}
|
||||
\begin{itemize}
|
||||
\item Open Source Firmware
|
||||
|
|
@ -137,19 +128,21 @@ Cooler: \href{https://micropython.org/}{MicroPython}
|
|||
\item Frei \& Open Source
|
||||
\item Einige Funktionalität eingeschränkt (z.B. Multithreading)
|
||||
\item Verscheidene Boards/Controller unterstützt: PyBoard, ESP32, \dots
|
||||
\item Doku: \url{http://docs.micropython.org/en/latest/esp8266/index.html} (\url{http://iot.wiai/doc})
|
||||
\item Doku: \url{https://docs.micropython.org/en/latest/esp8266/quickref.html} bzw. \url{https://docs.micropython.org/en/latest/esp32/quickref.html}
|
||||
\end{itemize}
|
||||
Lowlevel: C, Arduino Studio
|
||||
\end{frame}
|
||||
|
||||
\section{Setup}
|
||||
\subsection{Tools}
|
||||
\begin{frame}{Tools}\framesubtitle{Alle Downloads unter \url{http://iot.wiai/}}
|
||||
\begin{frame}{Tools}
|
||||
Linux
|
||||
\begin{itemize}
|
||||
\item Debian, Gentoo (testing): \texttt{\{apt install,emerge\} esptool picocom}
|
||||
\item Ubuntu: \texttt{pip3 install esptool \&\& apt install picocom}
|
||||
\item \texttt{adduser \$USER dialout}
|
||||
\item Alternative: Docker (bin/docker): \textit{docker-compose run esp esptool}
|
||||
\item neuer Login (sudo su \$USER)
|
||||
%\item Alternative: Docker (bin/docker): \textit{docker-compose run esp esptool}
|
||||
\end{itemize}
|
||||
Windows
|
||||
\begin{itemize}
|
||||
|
|
@ -159,32 +152,46 @@ Windows
|
|||
\end{itemize}
|
||||
\item \texttt{pip install esptool}
|
||||
\item \url{https://www.chiark.greenend.org.uk/~sgtatham/putty/download.html}
|
||||
\item CH340G Treiber: \url{http://www.wch.cn/download/CH341SER\_ZIP.html}
|
||||
\item CH340G Treiber: \url{https://www.silabs.com/products/development-tools/software/usb-to-uart-bridge-vcp-drivers}
|
||||
\end{itemize}
|
||||
Mac
|
||||
\begin{itemize}
|
||||
\item Homebrew (\url{https://brew.sh}) installieren + \texttt{brew install python3 \&\& pip install esptool}
|
||||
\item Homebrew (\url{https://brew.sh}) installieren
|
||||
\item \texttt{brew install python3 \&\& pip install esptool}
|
||||
\end{itemize}
|
||||
Offline pip: \textit{pip install -f http://iot.wiai/webrepl/}%TODO: --no-index?
|
||||
\end{frame}
|
||||
|
||||
\subsection{Firmware}
|
||||
\begin{frame}{Firmware}\framesubtitle{Alle Downloads unter \url{http://iot.wiai/}}
|
||||
\begin{frame}{Firmware ESP8266}
|
||||
Windows-Spezial:
|
||||
\begin{itemize}
|
||||
\item Portbezeichner: Gerätemanager $\rightarrow$ Serielle Geräte (COM+LPT) $\rightarrow$ COM$X$
|
||||
\item python -m esptool
|
||||
\item Portbezeichner: Gerätemanager $\rightarrow$ Serielle Geräte (COM+LPT) $\rightarrow$ COM$X$ (z.B. COM12)
|
||||
\end{itemize}
|
||||
Flashen:
|
||||
\begin{itemize}
|
||||
\item \url{https://micropython.org/download\#esp8266} %TODO: WIAI-link
|
||||
\item[*nix] \texttt{esptool.py --port /dev/ttyUSB0 erase\_flash}
|
||||
\item[win] \texttt{python -m esptool --port COM12 erase\_flash}
|
||||
\item[*nix] \texttt{esptool.py --port /dev/ttyUSB0 --baud 460800 write\_flash --flash\_size=detect 0 esp8266-20170823-v1.9.2.bin}
|
||||
\item[win] \texttt{python -m esptool --port COM12 --baud 460800 write\_flash --flash\_size=detect 0 esp8266-20170823-v1.9.2.bin}
|
||||
\item MicroPython Download: \url{https://micropython.org/download\#esp8266} (esp8266-20190125-v1.10.bin)
|
||||
\item[*nix] \texttt{esptool -{}-port /dev/ttyUSB0 erase\_flash}
|
||||
\item[win] \texttt{python -m esptool -{}-port COM12 erase\_flash}
|
||||
\item[*nix] \texttt{esptool -{}-port /dev/ttyUSB0 -{}-baud 460800 write\_flash -{}-flash\_size=detect 0 esp8266-20190125-v1.10.bin}
|
||||
\item[win] \texttt{python -m esptool -{}-port COM12 -{}-baud 460800 write\_flash -{}-flash\_size=detect 0 esp8266-20190125-v1.10.bin}
|
||||
\item reset
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
\begin{frame}{Firmware ESP32}
|
||||
Windows-Spezial:
|
||||
\begin{itemize}
|
||||
\item Portbezeichner: Gerätemanager $\rightarrow$ Serielle Geräte (COM+LPT) $\rightarrow$ COM$X$ (z.B. COM12)
|
||||
\end{itemize}
|
||||
Flashen:
|
||||
\begin{itemize}
|
||||
\item MicroPython Download: \url{https://micropython.org/download\#esp32} (esp32-20190128-v1.10-15-gdeb67569f.bin)
|
||||
\item[*nix] \texttt{esptool -{}-chip esp32 -{}-port /dev/ttyUSB0 -{}-baud 460800 write\_flash -z 0x1000 esp32-20190128-v1.10-15-gdeb67569f.bin}
|
||||
\item[win] \texttt{python -m esptool -{}-chip esp32 -{}-port COM12 -{}-baud 460800 write\_flash -z 0x1000 esp32-20190128-v1.10-15-gdeb67569f.bin}
|
||||
\item Während dessen wild auf Boot drücken...
|
||||
\item reset
|
||||
\item Troubleshooting: Evtl. \texttt{esptool.py} verwenden
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{REPL}
|
||||
\begin{frame}{Serielle Konsole}
|
||||
|
|
@ -192,8 +199,9 @@ Flashen:
|
|||
\begin{itemize}
|
||||
\item \texttt{picocom -b 115200 /dev/ttyUSB0}
|
||||
\item $n$ beherzte \textit{<ENTER>}-Drücke
|
||||
\item Docker: \texttt{docker-compose run esp} (evtl. TTY anpassen)
|
||||
%\item Docker: \texttt{docker-compose run esp} (evtl. TTY anpassen)
|
||||
\item[exit] Ctrl-a Ctrl-x
|
||||
\item Alternativ: screen, \dots
|
||||
\end{itemize}
|
||||
Windows:
|
||||
\begin{itemize}
|
||||
|
|
@ -214,7 +222,7 @@ Windows:
|
|||
|
||||
\subsection{WLAN}
|
||||
\begin{frame}[fragile]{WLAN}\framesubtitle{Put the I in IoT}
|
||||
\begin{lstlisting}[caption={Descriptive Caption Text},label=DescriptiveLabel]
|
||||
\begin{lstlisting}[caption={Wifi Setup},label=DescriptiveLabel]
|
||||
import network
|
||||
sta_if = network.WLAN(network.STA_IF)
|
||||
ap_if = network.WLAN(network.AP_IF)
|
||||
|
|
@ -222,7 +230,7 @@ ap_if = network.WLAN(network.AP_IF)
|
|||
ap_if.active(False)
|
||||
sta_if.active(True)
|
||||
|
||||
sta_if.connect('SSID', 'SECRET') # TODO: setup
|
||||
sta_if.connect('wiaiot', 'wiaiotoiaiw')
|
||||
sta_if.isconnected()
|
||||
sta_if.ifconfig()
|
||||
\end{lstlisting}
|
||||
|
|
@ -234,18 +242,20 @@ import webrepl_setup
|
|||
\end{lstlisting}
|
||||
\begin{itemize}
|
||||
\item \textit{import webrepl\_setup}
|
||||
\item reset/start webrepl (\textit{import webrepl \& webrepl.start()})
|
||||
\item visit \url{http://iot.wiai/webrepl/} or \url{http://micropython.org/webrepl/}
|
||||
\item enter your ESP's IP (\textit{sta\_if.ifconfig()}) \& connect
|
||||
\item WebREPL einrichten (\textit{import webrepl \& webrepl.start()})
|
||||
\item WebREPL Client \url{http://micropython.org/webrepl/}
|
||||
\item IP des ESP's für WebSocket verwenden (\textit{sta\_if.ifconfig()})
|
||||
\item Datei Up-/Download (z.B. für main.py)
|
||||
\end{itemize}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Init}
|
||||
\begin{frame}[fragile]{main.py}
|
||||
Wird beim starten ... gestartet
|
||||
Wird beim starten \dots gestartet
|
||||
|
||||
\begin{lstlisting}[caption={main.py},label=mainpy]
|
||||
def connect_wifi(ssid, passphrase):
|
||||
from secrets import SSID, PASS
|
||||
def connect_wifi(ssid=SSID, passphrase=PASS):
|
||||
#TODO ;)
|
||||
pass
|
||||
|
||||
|
|
@ -258,40 +268,40 @@ setup()
|
|||
\end{lstlisting}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Exkurs: Flask-Server}
|
||||
\begin{frame}[fragile]{Gegenseite: Flask}
|
||||
\begin{lstlisting}[caption={C\&C Server},label=cnc]
|
||||
from flask import Flask, request
|
||||
app = Flask(__name__)
|
||||
@app.route("/")
|
||||
def hello():
|
||||
return "Hello ESP8266!"
|
||||
@app.route("/id/<id:id>", methods=['GET','POST'])
|
||||
def log(id):
|
||||
app.logger.info("%s was here and delivered '%s'", id, request.data.decode("utf8"))
|
||||
\subsection{Exkurs: Grafana}
|
||||
\begin{frame}[fragile]{Gegenseite: InfluxDB + Grafana}
|
||||
|
||||
\begin{lstlisting}[caption={Collection Server (docker-compose)},label=cnc]
|
||||
version: "3"
|
||||
services:
|
||||
influxdb:
|
||||
image: influxdb:1.7-alpine
|
||||
|
||||
grafana:
|
||||
image: grafana/grafana:5.4.3
|
||||
networks:
|
||||
- traefik_net
|
||||
- default
|
||||
labels:
|
||||
- "traefik.enable=true"
|
||||
- "traefik.docker.network=traefik_net"
|
||||
- "traefik.http.frontend.rule=Host:iot.uni.clkl.de"
|
||||
|
||||
\end{lstlisting}
|
||||
Starten:
|
||||
\begin{itemize}
|
||||
\item[!] pip install Flask
|
||||
\item python server.py
|
||||
\item[||] docker-compose up (server.py in src/)
|
||||
\item[||] FLASK\_APP=server.py flask run
|
||||
\end{itemize}
|
||||
|
||||
\end{frame}
|
||||
|
||||
\begin{frame}[fragile]{Daten übertragen}
|
||||
\begin{lstlisting}[caption={HTTP Requests},label=http]
|
||||
import urequests
|
||||
host = "http://your.host.ip.here:5000"
|
||||
response = urequests.get(host)
|
||||
print(response)
|
||||
host = "http://iot-db.uni.clkl.de"
|
||||
#response = urequests.get(host)
|
||||
|
||||
import machine
|
||||
board_id = int.from_bytes(machine.unique_id(), 'little')
|
||||
payload = '{"board": "{id}"}'.format(id=board_id)
|
||||
json_header = {'Content-Type': 'application/json'}
|
||||
post_url = "{host}/id/{id}".format(host=host, id=board_id)
|
||||
urequests.post(post_url, data=data, headers=json_header)
|
||||
data = "machine_id,user=<you>,other_data=foobar value=" + str(board_id)
|
||||
post_url = "{host}/write?db={db}".format(host=host, db="ids")
|
||||
urequests.post(post_url, data=data)
|
||||
\end{lstlisting}
|
||||
\end{frame}
|
||||
|
||||
|
|
@ -338,7 +348,7 @@ pin.irq(trigger=machine.Pin.IRQ_RISING | machine.Pin.IRQ_FALLING, handler=callba
|
|||
\end{lstlisting}
|
||||
\end{frame}
|
||||
\subsection{Sensoren}
|
||||
\begin{frame}[fragile]{Sensoren}
|
||||
\begin{frame}[fragile]{DHT22}
|
||||
\image{.35\textwidth}{nodemcu-dht22}{DHT22 \cite{node-dht}}{img:dht}
|
||||
\begin{lstlisting}[caption={Sensoren},label=senors]
|
||||
import dht
|
||||
|
|
@ -349,16 +359,36 @@ d.temperature()
|
|||
d.humidity()
|
||||
\end{lstlisting}
|
||||
\end{frame}
|
||||
\begin{frame}[fragile]{BME280}
|
||||
\image{.25\textwidth}{esp-bme}{BME 280 \cite{espbme}}{img:bme}
|
||||
Modul auf ESP hochladen: bem280.py \cite{bmemod}
|
||||
\begin{lstlisting}[caption={Sensoren},label=senors]
|
||||
import bme280
|
||||
import machine
|
||||
i2c=machine.I2C(scl=machine.Pin(26),sda=machine.Pin(25))
|
||||
bme=bme280.BME280(i2c=i2c)
|
||||
|
||||
bme.values
|
||||
\end{lstlisting}
|
||||
\end{frame}
|
||||
|
||||
\subsection{Interrupts}
|
||||
\begin{frame}{Here be dragons}
|
||||
\begin{frame}{Interrupts}
|
||||
\framesubtitle{Here be dragons}
|
||||
\begin{itemize}
|
||||
\item Z.B. Callbacks von Tastern
|
||||
\item pausieren main
|
||||
\item dürfen keinen Speicher allozieren
|
||||
\begin{itemize}
|
||||
\item[\checkmark] \textit{alarm = True \#only with previously allocated variable!}
|
||||
\item[\checkmark] \textit{counter = counter + 1}
|
||||
\item[\checkmark] \textit{interrupts[2] += 1}
|
||||
\item[X] \textit{events.append(Interrupt())}
|
||||
\item[X] \textit{}
|
||||
\end{itemize}
|
||||
\item Emergency exception buffer: \textit{micropython.alloc\_emergency\_exception\_buf(100)}
|
||||
\end{itemize}
|
||||
\cite{mp-interrupt}
|
||||
Siehe Doku :) \cite{mp-interrupt}
|
||||
\end{frame}
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
|
|
|
|||