├── .cproject ├── .gitignore ├── .project ├── .pydevproject ├── .settings ├── language.settings.xml └── org.eclipse.cdt.codan.core.prefs ├── CHANGELOG.md ├── Jenkinsfile ├── LICENSE ├── Makefile ├── README.md ├── bin ├── coredump.sh ├── coredump2.sh ├── debug.sh ├── deploy_ota.sh ├── dev_tests.sh ├── erase.sh ├── find_esp_device.py ├── firmware_installer.py ├── flash-monitor.sh ├── make_default.sh ├── make_test_menuconfig.sh ├── make_tests.sh ├── read_serial.py ├── run_tests.py └── test_components.sh ├── components ├── oap-aws │ ├── awsiot.c │ ├── awsiot_common.h │ ├── awsiot_rest.c │ ├── awsiot_rest.h │ ├── component.mk │ ├── include │ │ └── awsiot.h │ ├── test │ │ ├── 1cbf751210-certificate.pem.crt │ │ ├── 1cbf751210-private.pem.key │ │ ├── 1cbf751210-public.pem.key │ │ ├── component.mk │ │ └── test_awsiot.c │ └── verisign_root_ca.pem ├── oap-common │ ├── c_list.c │ ├── component.mk │ ├── default_config.json │ ├── include │ │ ├── c_list.h │ │ ├── oap_common.h │ │ ├── oap_data.h │ │ ├── oap_data_env.h │ │ ├── oap_data_pm.h │ │ ├── oap_debug.h │ │ ├── oap_publisher.h │ │ ├── oap_storage.h │ │ └── oap_version.h │ ├── oap_common.c │ ├── oap_debug.c │ ├── oap_storage.c │ ├── oap_version.c │ └── test │ │ ├── .gitignore │ │ ├── component.mk │ │ ├── include │ │ └── oap_test.h │ │ ├── oap_test.c │ │ ├── sandbox.c │ │ ├── test_oap_storage.c │ │ └── test_oap_version.c ├── oap-http │ ├── LICENSE │ ├── README.md │ ├── component.mk │ ├── esp_request.c │ ├── include │ │ ├── esp_request.h │ │ ├── req_list.h │ │ └── uri_parser.h │ ├── req_list.c │ ├── test │ │ ├── component.mk │ │ └── test_esp_request.c │ └── uri_parser.c ├── oap-hw-bmx280 │ ├── Kconfig │ ├── bmx280.c │ ├── component.mk │ ├── i2c_bme280.c │ ├── i2c_bme280.h │ ├── include │ │ └── bmx280.h │ └── test │ │ ├── component.mk │ │ └── test_bmx280.c ├── oap-hw-ext │ ├── Kconfig │ ├── component.mk │ ├── ctrl_btn.c │ ├── include │ │ ├── ctrl_btn.h │ │ └── rgb_led.h │ └── rgb_led.c ├── oap-hw-pmsx003 │ ├── Kconfig │ ├── component.mk │ ├── include │ │ └── pmsx003.h │ ├── pmsx003.c │ └── test │ │ ├── component.mk │ │ └── test_pmsx003.c ├── oap-meter │ ├── Kconfig │ ├── component.mk │ ├── include │ │ ├── meas_continuous.h │ │ ├── meas_intervals.h │ │ └── pm_meter.h │ ├── meas_continuous.c │ ├── meas_intervals.c │ ├── pm_meter.c │ └── test │ │ ├── component.mk │ │ └── test_pm_meter.c ├── oap-ota │ ├── Kconfig │ ├── comodo_ca.pem │ ├── component.mk │ ├── digicert_ca.crt │ ├── digicert_ca.pem │ ├── include │ │ └── ota.h │ ├── ota.c │ ├── ota_int.h │ └── test │ │ ├── component.mk │ │ ├── files │ │ ├── hello-world.bin │ │ ├── index-sha-mismatch.txt │ │ └── index.txt │ │ └── test_ota.c ├── oap-thingspk │ ├── component.mk │ ├── include │ │ └── thing_speak.h │ ├── test │ │ ├── component.mk │ │ └── test_thing_speak.c │ └── thing_speak.c └── oap-wifi │ ├── Kconfig │ ├── bootwifi.c │ ├── component.mk │ ├── cpanel.c │ ├── cpanel.h │ ├── include │ ├── bootwifi.h │ └── server_cpanel.h │ ├── index.html │ ├── mongoose.c │ ├── mongoose.h │ ├── server.c │ ├── server.h │ ├── server_cpanel.c │ └── test │ ├── component.mk │ └── test_bootwifi.c ├── doc ├── BST-BME280_DS001-10.pdf ├── BST-BMP280-DS001-11.pdf ├── api │ ├── README.md │ └── state.json ├── images │ ├── ESP32-DevBoard.jpg │ ├── prototype.jpg │ ├── schema.jpg │ └── sensor_settings.png └── plantower-pms5003-manual_v2-3.pdf ├── main ├── Kconfig.projbuild ├── component.mk ├── main.c └── oap_config.txt ├── partitions.csv ├── sdkconfig.defaults └── unit-test-app ├── .gitignore ├── Makefile ├── README.md ├── components └── unity │ ├── component.mk │ ├── include │ ├── test_utils.h │ ├── unity.h │ ├── unity_config.h │ └── unity_internals.h │ ├── license.txt │ ├── ref_clock.c │ ├── test_utils.c │ ├── unity.c │ └── unity_platform.c ├── main ├── app_main.c └── component.mk ├── partition_table_unit_test_app.csv └── sdkconfig.defaults /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | sdkconfig 3 | sdkconfig.old 4 | sdkconfig.bak 5 | .DS_Store 6 | main/*.bak 7 | core.dat 8 | /tmp 9 | /logs -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | pmsensor 4 | 5 | 6 | 7 | 8 | 9 | org.python.pydev.PyDevBuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.cdt.managedbuilder.core.genmakebuilder 15 | clean,full,incremental, 16 | 17 | 18 | 19 | 20 | org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder 21 | full,incremental, 22 | 23 | 24 | 25 | 26 | 27 | org.eclipse.cdt.core.cnature 28 | org.eclipse.cdt.core.ccnature 29 | org.eclipse.cdt.managedbuilder.core.managedBuildNature 30 | org.eclipse.cdt.managedbuilder.core.ScannerConfigNature 31 | org.python.pydev.pythonNature 32 | 33 | 34 | -------------------------------------------------------------------------------- /.pydevproject: -------------------------------------------------------------------------------- 1 | 2 | 3 | Default 4 | python interpreter 5 | 6 | -------------------------------------------------------------------------------- /.settings/language.settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.2.0 2 | 3 | - a few IDF configuration changes (run on single core, reduce flash freq) 4 | - clean up logs 5 | - update esp-idf 2.1 to include KRACK fix 6 | 7 | # 1.1.0 8 | 9 | - reboot after crash or when watchdog detects hanging task for 10sec ([#43](https://github.com/openairproject/sensor-esp32/issues/43)) 10 | 11 | # 1.0.0 12 | 13 | - use stable esp-idf release instead of working version (too many issues with wifi/ssl) 14 | - ability to reset to factory firmware ([#40](https://github.com/openairproject/sensor-esp32/issues/40)) 15 | 16 | # 0.6.0 17 | 18 | - fix wifi issues ([#32](https://github.com/openairproject/sensor-esp32/issues/32)), ([#19](https://github.com/openairproject/sensor-esp32/issues/19)) 19 | - wifi / control panel refactored and unit-tested 20 | 21 | 22 | # 0.5.1 23 | 24 | - configurable OTA interval ([#28](https://github.com/openairproject/sensor-esp32/issues/28)) 25 | - refactored thingspeak client and generic 'publisher' interface 26 | 27 | # 0.5.0 28 | 29 | - enable Jenkins build and automated unit tests ([#4](https://github.com/openairproject/sensor-esp32/issues/4)) 30 | 31 | # 0.4.3 32 | 33 | - OTA updates ([#2](https://github.com/openairproject/sensor-esp32/issues/2)) 34 | - fix NVS crash after fresh install ([#14](https://github.com/openairproject/sensor-esp32/issues/14)) 35 | - fix non-unique SSID in AP mode ([#21](https://github.com/openairproject/sensor-esp32/issues/21)) 36 | 37 | # 0.4.0 38 | 39 | - support two PM sensors ([#8](https://github.com/openairproject/sensor-esp32/issues/8)) 40 | - update ESP-IDF to 2.1 ([#1](https://github.com/openairproject/sensor-esp32/issues/1)) 41 | - track firmware version ([#9](https://github.com/openairproject/sensor-esp32/issues/9)) 42 | - display firmware version ([#11](https://github.com/openairproject/sensor-esp32/issues/11)) 43 | - add unit tests ([#3](https://github.com/openairproject/sensor-esp32/issues/3)) 44 | 45 | # 0.3.0 46 | 47 | - support two (internal and external) bmx sensors 48 | - support optional fan and heater 49 | 50 | # 0.2.0 51 | 52 | - support for bmp280 and bme280 53 | - basic rest client for AWS IoT 54 | 55 | # 0.1.1 56 | 57 | - all main features working (some issues with bmp280) 58 | - thingspeak client 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | pipeline { 2 | agent any 3 | stages { 4 | stage('build') { 5 | steps { 6 | checkout scm 7 | sh 'rm -rf build' 8 | sh 'bin/make_default.sh' 9 | } 10 | } 11 | stage('test') { 12 | steps { 13 | sh '/opt/oap/dev/tty_refresh.sh' 14 | sh 'bin/make_tests.sh' 15 | sh 'sleep 3' 16 | sh 'bin/run_tests.py /opt/oap/dev/ttyOAP.TEST' 17 | } 18 | } 19 | stage('archive') { 20 | steps { 21 | sh 'cat build/sensor-esp32.bin | openssl dgst -sha256 > build/sensor-esp32.bin.sha256' 22 | } 23 | post { 24 | success { 25 | archiveArtifacts artifacts: 'build/sensor-esp32.*', fingerprint: true 26 | archiveArtifacts artifacts: 'build/partitions.bin', fingerprint: true 27 | archiveArtifacts artifacts: 'build/bootloader/bootloader.bin', fingerprint: true 28 | } 29 | } 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := sensor-esp32 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | 10 | -------------------------------------------------------------------------------- /bin/coredump.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | $IDF_PATH/components/espcoredump/espcoredump.py info_corefile -t b64 -c logs/core.dat build/sensor-esp32.elf -------------------------------------------------------------------------------- /bin/coredump2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | $IDF_PATH/components/espcoredump/espcoredump.py dbg_corefile -t b64 -c logs/core.dat build/sensor-esp32.elf -------------------------------------------------------------------------------- /bin/debug.sh: -------------------------------------------------------------------------------- 1 | xtensa-esp32-elf-gdb build/sensor-esp32.elf 2 | -------------------------------------------------------------------------------- /bin/deploy_ota.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # $1 - release version 5 | # 6 | 7 | INDEX_FILE=build/index.txt 8 | DEST_FOLDER=s3://openairproject.com/ota 9 | 10 | printf "$1|$1/sensor-esp32.bin|" > $INDEX_FILE 11 | 12 | cat build/sensor-esp32.bin | openssl dgst -sha256 -binary | xxd -p -c 100 >> $INDEX_FILE 13 | cat $INDEX_FILE 14 | 15 | aws s3 cp build/sensor-esp32.bin $DEST_FOLDER/$1/sensor-esp32.bin --profile oap 16 | aws s3 cp $INDEX_FILE $DEST_FOLDER/index.txt --profile oap -------------------------------------------------------------------------------- /bin/dev_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #https://www.esp32.com/viewtopic.php?t=2867 4 | 5 | bin="$(dirname "$0")" 6 | . bin/test_components.sh 7 | project=`pwd` 8 | echo $TEST_COMPONENTS 9 | make -C unit-test-app EXTRA_COMPONENT_DIRS=$project/components TEST_COMPONENTS="$TEST_COMPONENTS" all flash monitor -j5 -------------------------------------------------------------------------------- /bin/erase.sh: -------------------------------------------------------------------------------- 1 | python $IDF_PATH/components/esptool_py/esptool/esptool.py -p /opt/oap/dev/ttyOAP -b 115200 erase_flash 2 | -------------------------------------------------------------------------------- /bin/find_esp_device.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | 3 | import sys 4 | import glob 5 | import subprocess 6 | import os 7 | import re 8 | 9 | # 10 | # allows mapping connected ESP32 devices based on their chipId. 11 | # Using chipId is necessary since all devboards report the same serial num and other 12 | # attrbbutes that are usually used to map serial devices to persistent names 13 | # 14 | # Usage: 15 | # 16 | # find_esp_devices.py '/dev/ttyUSB?' '0xac240ac4020c' '$HOME/dev1' '0xd30aea4014e' '$HOME/dev0' 17 | # 18 | # 1st argument is a mask to look for connected devices, 19 | # then each pair of arguments defines a mapping between chipId => symlink to create 20 | # 21 | # chipId must be in the exact format as returned by esptool. 22 | # You can display it using 23 | # 24 | # esptool.py --port '/dev/ttyUSB0' chip_id 25 | # 26 | 27 | chipToSymlink={} 28 | for i in xrange(2, len(sys.argv), 2): 29 | chipToSymlink[sys.argv[i].strip()]=os.path.expandvars(sys.argv[i+1].strip()) 30 | 31 | print 'look for devices \"'+sys.argv[1]+'\" and try to map links ', 32 | print chipToSymlink 33 | 34 | devices = glob.glob(sys.argv[1]) 35 | 36 | esptool = os.path.expandvars('$IDF_PATH')+'/components/esptool_py/esptool/esptool.py' 37 | print 'esp tool path: '+esptool 38 | 39 | chipToTTY={} 40 | 41 | for device in devices: 42 | print 'checking '+device 43 | proc = subprocess.Popen([esptool,'--port',device,'chip_id'],stdout=subprocess.PIPE) 44 | while True: 45 | line = proc.stdout.readline() 46 | if line == '': 47 | break 48 | matcher = re.match('Chip ID: (0x.*)', line, re.M|re.I) 49 | if matcher: 50 | print 'chip:'+matcher.group(1) 51 | chipToTTY[matcher.group(1)]=device 52 | break 53 | 54 | proc.wait() 55 | if proc.returncode != 0: 56 | print 'exit due to problem with esptool ('+proc.returncode+')' 57 | sys.exit(proc.returncode) 58 | 59 | print 'found following devices ', 60 | print chipToTTY 61 | 62 | for chipId in chipToSymlink: 63 | link = chipToSymlink[chipId] 64 | if os.path.islink(link): 65 | os.unlink(link) 66 | try: 67 | tty = chipToTTY[chipId] 68 | print 'create link '+link+'=>'+tty 69 | os.symlink(tty, link) 70 | except KeyError, e: 71 | pass 72 | 73 | print 'done' -------------------------------------------------------------------------------- /bin/firmware_installer.py: -------------------------------------------------------------------------------- 1 | 1. ask for UART NAME 2 | 2. 3 | make TEMP_DIR 4 | git clone https://github.com/espressif/esptool.git -o TEMP_DIR 5 | 3. 6 | TEMP_DIR/esptool.py --port /dev/tty.SLAB_USBtoUART --after no_reset chip_id 7 | 4. 8 | fetch https://openairproject.com/ota/index.txt to TEMP_DIR 9 | parse first line 10 | fetch binaries to TEMP_DIR 11 | test sha 12 | 5. 13 | fetch partitions_two_ota.bin 14 | fetch bootloader.bin 15 | 6. 16 | python TEMP_DIR/esptool.py --chip esp32 --port /dev/tty.SLAB_USBtoUART --baud 921600 --before default_reset 17 | --after hard_reset write_flash -u --flash_mode dio --flash_freq 40m --flash_size detect 18 | 0x1000 TEMP_DIR/bootloader.bin 0x10000 TEMP_DIR/sensor-esp32.bin 0x8000 TEMP_DIR/partitions_two_ota.bin -------------------------------------------------------------------------------- /bin/flash-monitor.sh: -------------------------------------------------------------------------------- 1 | make flash monitor -j5 | tee logs/`date +%Y-%m-%d%H%M`.log 2 | 3 | -------------------------------------------------------------------------------- /bin/make_default.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | export BATCH_BUILD=1 4 | make defconfig all $1 -j5 > /dev/null -------------------------------------------------------------------------------- /bin/make_test_menuconfig.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | bin="$(dirname "$0")" 4 | . bin/test_components.sh 5 | project=`pwd` 6 | echo $TEST_COMPONENTS 7 | make -C unit-test-app EXTRA_COMPONENT_DIRS=$project/components TEST_COMPONENTS="$TEST_COMPONENTS" menuconfig -------------------------------------------------------------------------------- /bin/make_tests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | #https://www.esp32.com/viewtopic.php?t=2867 4 | 5 | bin="$(dirname "$0")" 6 | . bin/test_components.sh 7 | export BATCH_BUILD=1 8 | project=`pwd` 9 | 10 | make -C unit-test-app EXTRA_COMPONENT_DIRS=$project/components TEST_COMPONENTS="$TEST_COMPONENTS" defconfig all flash $1 -j5 > /dev/null -------------------------------------------------------------------------------- /bin/read_serial.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import serial 3 | import sys 4 | import time 5 | 6 | ser = serial.Serial(None,115200,timeout=None,rtscts=False,xonxoff=True) 7 | ser.port=sys.argv[1] 8 | ser.dtr=False 9 | ser.rts=False #otherwise it will wait for download after reboot 10 | ser.open() 11 | 12 | try: 13 | while True: 14 | line = ser.readline() 15 | print line, 16 | #to work with 'tee' 17 | sys.stdout.flush() 18 | finally: 19 | ser.close() -------------------------------------------------------------------------------- /bin/run_tests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import serial 3 | import sys 4 | import time 5 | 6 | #'/dev/tty.SLAB_USBtoUART' 7 | 8 | ser = serial.Serial(sys.argv[1],115200,timeout=1) 9 | 10 | def readall(exp, timeout = 5): 11 | line = ser.readline() 12 | lastline = '' 13 | start = time.time() 14 | while line != exp: 15 | lastline = line 16 | 17 | if line == 'Rebooting...': 18 | lastline = 'UNEXPECTED REBOOT' 19 | break 20 | 21 | if ":FAIL" in line or ":PASS" in line: 22 | start = time.time() 23 | 24 | if time.time() - start > timeout: 25 | lastline = 'TIMEOUT after '+str(timeout)+' seconds' 26 | break 27 | 28 | line = ser.readline() 29 | sys.stdout.write(line) 30 | sys.stdout.flush() 31 | line = line.strip() 32 | return lastline 33 | 34 | def wait_for_test_result(): 35 | return readall('Enter next test, or \'enter\' to see menu',30) 36 | 37 | ser.write('\n'); 38 | readall('Here\'s the test menu, pick your combo:') 39 | readall('') 40 | ser.write('*' if len(sys.argv) <= 2 else sys.argv[2]) 41 | ser.write('\n') 42 | result = wait_for_test_result().strip() 43 | sys.stdout.write('TEST RESULT: '+result) 44 | ser.close() 45 | sys.exit(0 if result == 'OK' else 1) -------------------------------------------------------------------------------- /bin/test_components.sh: -------------------------------------------------------------------------------- 1 | TEST_COMPONENTS='oap-common oap-hw-bmx280 oap-hw-pmsx003 oap-meter oap-http oap-aws oap-thingspk oap-ota oap-wifi' -------------------------------------------------------------------------------- /components/oap-aws/awsiot_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * awsiot_common.h 3 | * 4 | * Created on: Feb 18, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_AWSIOT_AWSIOT_COMMON_H_ 24 | #define COMPONENTS_AWSIOT_AWSIOT_COMMON_H_ 25 | 26 | 27 | 28 | 29 | 30 | #endif /* COMPONENTS_AWSIOT_AWSIOT_COMMON_H_ */ 31 | -------------------------------------------------------------------------------- /components/oap-aws/awsiot_rest.c: -------------------------------------------------------------------------------- 1 | /* 2 | * aws_iot_rest.c 3 | * 4 | * Created on: Feb 18, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include 24 | #include 25 | #include "freertos/FreeRTOS.h" 26 | #include "freertos/task.h" 27 | #include "freertos/event_groups.h" 28 | #include "esp_wifi.h" 29 | #include "esp_event_loop.h" 30 | #include "esp_log.h" 31 | #include "esp_system.h" 32 | #include "nvs_flash.h" 33 | 34 | #include "awsiot_rest.h" 35 | //#include "ssl_client.h" 36 | #include "oap_common.h" 37 | #include "oap_debug.h" 38 | #include "esp_request.h" 39 | 40 | //#define WEB_SERVER "a32on3oilq3poc.iot.eu-west-1.amazonaws.com" 41 | //#define WEB_PORT "8443" 42 | //#define WEB_URL "/things/pm_wro_2/shadow" 43 | 44 | static const char *TAG = "awsiot"; 45 | 46 | extern const uint8_t verisign_root_ca_pem_start[] asm("_binary_verisign_root_ca_pem_start"); 47 | extern const uint8_t verisign_root_ca_pem_end[] asm("_binary_verisign_root_ca_pem_end"); 48 | 49 | static int download_callback(request_t *req, char *data, int len) { 50 | ESP_LOGI(TAG, "response:%s", data); 51 | return 0; 52 | } 53 | 54 | esp_err_t awsiot_update_shadow(awsiot_config_t* awsiot_config, char* body) { 55 | char uri[100]; 56 | sprintf(uri, "https://%s:%d", awsiot_config->endpoint, awsiot_config->port); 57 | 58 | request_t* req = req_new(uri); 59 | if (!req) { 60 | return ESP_FAIL; 61 | } 62 | 63 | req->ca_cert = req_parse_x509_crt((unsigned char*)verisign_root_ca_pem_start, verisign_root_ca_pem_end-verisign_root_ca_pem_start); 64 | if (!req->ca_cert) { 65 | req_clean(req); 66 | ESP_LOGW(TAG, "Invalid CA cert"); 67 | return ESP_FAIL; 68 | } 69 | 70 | req->client_cert = req_parse_x509_crt((unsigned char*)awsiot_config->cert, strlen(awsiot_config->cert)+1); 71 | if (!req->client_cert) { 72 | req_clean(req); 73 | ESP_LOGW(TAG, "Invalid client cert"); 74 | return ESP_FAIL; 75 | } 76 | req->client_key = req_parse_pkey((unsigned char*)awsiot_config->pkey, strlen(awsiot_config->pkey)+1); 77 | 78 | if (!req->client_key) { 79 | req_clean(req); 80 | ESP_LOGW(TAG, "Invalid client key"); 81 | return ESP_FAIL; 82 | } 83 | 84 | char path[100]; 85 | sprintf(path, "/things/%s/shadow", awsiot_config->thingName); 86 | 87 | 88 | req_setopt(req, REQ_SET_METHOD, HTTP_POST); 89 | req_setopt(req, REQ_SET_PATH, path); 90 | //req_setopt(req, REQ_SET_HEADER, host_header); 91 | req_setopt(req, REQ_SET_HEADER, HTTP_HEADER_CONTENT_TYPE_JSON); 92 | req_setopt(req, REQ_SET_HEADER, HTTP_HEADER_CONNECTION_CLOSE); 93 | req_setopt(req, REQ_SET_DATAFIELDS, body); 94 | 95 | req_setopt(req, REQ_FUNC_DOWNLOAD_CB, download_callback); 96 | 97 | int status = req_perform(req); 98 | req_clean(req); 99 | 100 | if (status != 200) { 101 | ESP_LOGW(TAG, "Invalid response code: %d", status); 102 | return ESP_FAIL; 103 | } else { 104 | return ESP_OK; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /components/oap-aws/awsiot_rest.h: -------------------------------------------------------------------------------- 1 | /* 2 | * awsiot_rest.h 3 | * 4 | * Created on: Feb 18, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_AWSIOT_INCLUDE_AWSIOT_REST_H_ 24 | #define COMPONENTS_AWSIOT_INCLUDE_AWSIOT_REST_H_ 25 | 26 | typedef struct { 27 | int configured; 28 | char* endpoint; 29 | int port; 30 | char* thingName; 31 | char* cert; 32 | char* pkey; 33 | } awsiot_config_t; 34 | 35 | esp_err_t awsiot_update_shadow(awsiot_config_t* awsiot_config, char* body); 36 | 37 | #endif /* COMPONENTS_AWSIOT_INCLUDE_AWSIOT_REST_H_ */ 38 | -------------------------------------------------------------------------------- /components/oap-aws/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | COMPONENT_EMBED_TXTFILES := verisign_root_ca.pem -------------------------------------------------------------------------------- /components/oap-aws/include/awsiot.h: -------------------------------------------------------------------------------- 1 | /* 2 | * awsiot_client.h 3 | * 4 | * Created on: Feb 18, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_AWSIOT_INCLUDE_AWSIOT_H_ 24 | #define COMPONENTS_AWSIOT_INCLUDE_AWSIOT_H_ 25 | 26 | #include "oap_common.h" 27 | #include "oap_publisher.h" 28 | 29 | oap_publisher_t awsiot_publisher; 30 | 31 | #endif /* COMPONENTS_AWSIOT_INCLUDE_AWSIOT_H_ */ 32 | -------------------------------------------------------------------------------- /components/oap-aws/test/1cbf751210-certificate.pem.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDWjCCAkKgAwIBAgIVAKFzi5PjNi9O8WR8Nc5U8/vPVRZGMA0GCSqGSIb3DQEB 3 | CwUAME0xSzBJBgNVBAsMQkFtYXpvbiBXZWIgU2VydmljZXMgTz1BbWF6b24uY29t 4 | IEluYy4gTD1TZWF0dGxlIFNUPVdhc2hpbmd0b24gQz1VUzAeFw0xNzA5MTExOTE3 5 | MDdaFw00OTEyMzEyMzU5NTlaMB4xHDAaBgNVBAMME0FXUyBJb1QgQ2VydGlmaWNh 6 | dGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCWJaW0JqRg8pMYZm6L 7 | fSuMlGzAmElbArKDXe4f+LA3dzsSZG7ZxX6p/yEcPwx5dMtJjhq1BOlJu/pL+8Lk 8 | JkfluUeVt7oemdRJN1A/gcfwN+OY7bT1RQ3cGbeCZP5Y+APcfS1Cag25i0E9gweI 9 | Om9aEDb23hAr02FosQQjeaDOHpz4QelPnCGvyiQAktxjyG77RXRg0H9csgPwkklc 10 | fnEt0z9Bsh9dqdH5R6tkdJz8oTlbBFC5VLu20Kcu1LdG82GIJ6p24uXcJLKNWcsm 11 | 6Cc/nqxfxTkzKrgI+4si4Yya/nUJSkTYnnFW8zgk3Fw8dNCnpfMfgyZ0mhoXOvFt 12 | 7iKPAgMBAAGjYDBeMB8GA1UdIwQYMBaAFKQWUtvRdE8V1KemiV6qOWgmc+86MB0G 13 | A1UdDgQWBBRkSSPHlb6NyJff0KbedYJCRIxFXzAMBgNVHRMBAf8EAjAAMA4GA1Ud 14 | DwEB/wQEAwIHgDANBgkqhkiG9w0BAQsFAAOCAQEAfptO2uTC3w1r5dIsv/CaURns 15 | xGyvOBKKwl3kZdSMDSvRYpktVBSbQLMcBx35eutvlc/ICgV0PoBUKtcSFuYSHP7n 16 | 4zPSU7mDoAaX3sikLLPzZMxHmWalhJMKezl9leRJsJKPa7YTqelaaZAuq6w8G6x8 17 | Q+1LIeSUrPr0yN4+uCW1VdtZT6AVYD+rnjLhmUx6HvhKSbByR1oMsuDExckTpIAO 18 | TOpmQ2jB7xISa2n9zCgndqZd3TsVhOKtQ6kAWw208O6aHhEcLamQiv2X2XgZhbZg 19 | slJkauJ8k+s9Uv+I/0pBcTfWathGsnuKXogIlqKRud6J0Mv4lZqHb0Oq/Kp3tg== 20 | -----END CERTIFICATE----- 21 | -------------------------------------------------------------------------------- /components/oap-aws/test/1cbf751210-private.pem.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEpAIBAAKCAQEAliWltCakYPKTGGZui30rjJRswJhJWwKyg13uH/iwN3c7EmRu 3 | 2cV+qf8hHD8MeXTLSY4atQTpSbv6S/vC5CZH5blHlbe6HpnUSTdQP4HH8DfjmO20 4 | 9UUN3Bm3gmT+WPgD3H0tQmoNuYtBPYMHiDpvWhA29t4QK9NhaLEEI3mgzh6c+EHp 5 | T5whr8okAJLcY8hu+0V0YNB/XLID8JJJXH5xLdM/QbIfXanR+UerZHSc/KE5WwRQ 6 | uVS7ttCnLtS3RvNhiCeqduLl3CSyjVnLJugnP56sX8U5Myq4CPuLIuGMmv51CUpE 7 | 2J5xVvM4JNxcPHTQp6XzH4MmdJoaFzrxbe4ijwIDAQABAoIBAQCSlji7tApBuDHR 8 | 3ZdJSa/ttK6kLUlYuD5uMJMd1Z682APtBe6PX9g0waeiuw9DuLoLmtgKKLxVx1cr 9 | PaVdNt50sjnoOpJT890kigMnrV308aubj19fIcbRPq5BeLY1SBYE+pToRUAXCJRu 10 | KHF/F4XFCRWQWOay0tFD86ZVuBY9hHcw1148hfMcQK7aDjrA1PKStAFi4gqeTcm+ 11 | UNFa7HNHq4LG7fuaEsmd9iBh9gooWsJiSmbcrG3knXwVJd2DuaTqou9jQqr/qQae 12 | CyB3uDEwbhSLx8ypMsiqSvoLO3qMRh/q359SfPnQCUS8EcbBELaOuSjE/em7DyPn 13 | wDnNbkpBAoGBANebbUx/Vmf8xAlro+aHqP4RFVMrCZNwbZMd05nA4nsZzSUo5ejq 14 | bgKzqcHHWvFDaxivO+33V4aJhId8NpfTN/3gHg+zZVAQHsJsPw7D7Wj/3yI2bfH+ 15 | R3NH823YWS2St4G2qua+u53rslnVUNFLx5mFVfN+pByt8FWkkDgzNFqvAoGBALJG 16 | vQiy2xYmq+Adg224La/u1LeTD2MGcdYqbQiZu8bhller5MwOweP4bvFU1NYGb7Ad 17 | 7xZim0mWEE0XXFKeivAWrO2GW6zTZaV1CzOjkOQzWxfV7vLcNd79ngJGbvs6EE2e 18 | ZYDgvuQfk7QM1lr1xKKVt143iFQJLmw5lEZ/DS4hAoGAfoIOUdJtqrpfdH+aPgvf 19 | lqQDdTdNeRuAz8+ydwb8XOq4ulMTA+V6A0/UDYWh0OqUDnnTmj+FNcW+45h4mAEx 20 | W1+DhAbpLV8oDUBih5Fi3jc0f+ib/mALIJNZPFyzhtANqKi8AoRrpa/EiH1n3Eaw 21 | qV3ZHvRx6voMiNP0Y2V4FLUCgYAHgrVqDWbveveYvIWR9MVv+QbbKQXn7RiUpjrr 22 | ttZTXaOg0+wSsLh4azn5TtKcpa7E463z6nmSUxEivk40aNt/m+TzKMrp8AoDO3ga 23 | V9S92HAJBAlKD/7xAwxKGj+Is/yF2Jt8H3vLTo1Bc50APgRnuRj9jidfKvfatV5K 24 | zgV3IQKBgQDN27WFS8rnhM6tgq+hwCoecPQjomHQnTb/RR6doSBIYh7sTm9iuFSi 25 | LjEfl1cGGaE2GP+SyPb2kvLnQSymd/S5LwffO33p1yGyhTXtl0vF7sy3VggBtpJl 26 | 8dNyo8v+IIYgmxZ0OT6YmCQZgi9bsJVEGmWnSn4iX1CGQXcAmU7XCg== 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /components/oap-aws/test/1cbf751210-public.pem.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAliWltCakYPKTGGZui30r 3 | jJRswJhJWwKyg13uH/iwN3c7EmRu2cV+qf8hHD8MeXTLSY4atQTpSbv6S/vC5CZH 4 | 5blHlbe6HpnUSTdQP4HH8DfjmO209UUN3Bm3gmT+WPgD3H0tQmoNuYtBPYMHiDpv 5 | WhA29t4QK9NhaLEEI3mgzh6c+EHpT5whr8okAJLcY8hu+0V0YNB/XLID8JJJXH5x 6 | LdM/QbIfXanR+UerZHSc/KE5WwRQuVS7ttCnLtS3RvNhiCeqduLl3CSyjVnLJugn 7 | P56sX8U5Myq4CPuLIuGMmv51CUpE2J5xVvM4JNxcPHTQp6XzH4MmdJoaFzrxbe4i 8 | jwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /components/oap-aws/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | 7 | COMPONENT_EMBED_TXTFILES := 1cbf751210-certificate.pem.crt 8 | COMPONENT_EMBED_TXTFILES += 1cbf751210-private.pem.key -------------------------------------------------------------------------------- /components/oap-aws/test/test_awsiot.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "unity.h" 6 | #include "oap_storage.h" 7 | #include "awsiot.h" 8 | #include "oap_test.h" 9 | 10 | static const char* TAG = "test_awsiot"; 11 | 12 | extern const uint8_t device_cert_pem_start[] asm("_binary_1cbf751210_certificate_pem_crt_start"); 13 | extern const uint8_t device_cert_pem_end[] asm("_binary_1cbf751210_certificate_pem_crt_end"); 14 | 15 | extern const uint8_t device_pkey_pem_start[] asm("_binary_1cbf751210_private_pem_key_start"); 16 | extern const uint8_t device_pkey_pem_end[] asm("_binary_1cbf751210_private_pem_key_end"); 17 | 18 | static esp_err_t publish() { 19 | oap_measurement_t meas = { 20 | .local_time = 1505156826 21 | }; 22 | 23 | oap_sensor_config_t sensor_config = { 24 | .0 25 | }; 26 | return awsiot_publisher.publish(&meas, &sensor_config); 27 | } 28 | 29 | static void setup() { 30 | cJSON* cfg = cJSON_CreateObject(); 31 | cJSON_AddNumberToObject(cfg, "enabled", 1); 32 | cJSON_AddStringToObject(cfg, "thingName", "test_device_1"); 33 | cJSON_AddStringToObject(cfg, "endpoint", "a32on3oilq3poc.iot.eu-west-1.amazonaws.com"); 34 | cJSON_AddNumberToObject(cfg, "port", 8443); 35 | char* cert = str_make((void*)device_cert_pem_start, device_cert_pem_end-device_cert_pem_start); 36 | char* pkey = str_make((void*)device_pkey_pem_start, device_pkey_pem_end-device_pkey_pem_start); 37 | cJSON_AddStringToObject(cfg, "cert", cert); 38 | cJSON_AddStringToObject(cfg, "pkey", pkey); 39 | 40 | TEST_ESP_OK(awsiot_publisher.configure(cfg)); 41 | cJSON_Delete(cfg); 42 | free(cert); 43 | free(pkey); 44 | } 45 | 46 | TEST_CASE("publish to awsiot", "[awsiot]") 47 | { 48 | setup(); 49 | test_require_wifi(); 50 | size_t curr_heap = 0; 51 | size_t prev_heap = 0; 52 | 53 | /* 54 | * heap consumption goes to 0 after ~40 requests 55 | */ 56 | for (int i = 0; i < 1; i++) { 57 | curr_heap = xPortGetFreeHeapSize(); 58 | ESP_LOGW(TAG, "REQUEST %d (heap %u, %d bytes)", i, curr_heap, curr_heap-prev_heap); 59 | prev_heap = curr_heap; 60 | TEST_ESP_OK(publish()); 61 | if (i) test_delay(1000); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /components/oap-aws/verisign_root_ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB 3 | yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL 4 | ExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJp 5 | U2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxW 6 | ZXJpU2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0 7 | aG9yaXR5IC0gRzUwHhcNMDYxMTA4MDAwMDAwWhcNMzYwNzE2MjM1OTU5WjCByjEL 8 | MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW 9 | ZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTowOAYDVQQLEzEoYykgMjAwNiBWZXJpU2ln 10 | biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MUUwQwYDVQQDEzxWZXJp 11 | U2lnbiBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9y 12 | aXR5IC0gRzUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvJAgIKXo1 13 | nmAMqudLO07cfLw8RRy7K+D+KQL5VwijZIUVJ/XxrcgxiV0i6CqqpkKzj/i5Vbex 14 | t0uz/o9+B1fs70PbZmIVYc9gDaTY3vjgw2IIPVQT60nKWVSFJuUrjxuf6/WhkcIz 15 | SdhDY2pSS9KP6HBRTdGJaXvHcPaz3BJ023tdS1bTlr8Vd6Gw9KIl8q8ckmcY5fQG 16 | BO+QueQA5N06tRn/Arr0PO7gi+s3i+z016zy9vA9r911kTMZHRxAy3QkGSGT2RT+ 17 | rCpSx4/VBEnkjWNHiDxpg8v+R70rfk/Fla4OndTRQ8Bnc+MUCH7lP59zuDMKz10/ 18 | NIeWiu5T6CUVAgMBAAGjgbIwga8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8E 19 | BAMCAQYwbQYIKwYBBQUHAQwEYTBfoV2gWzBZMFcwVRYJaW1hZ2UvZ2lmMCEwHzAH 20 | BgUrDgMCGgQUj+XTGoasjY5rw8+AatRIGCx7GS4wJRYjaHR0cDovL2xvZ28udmVy 21 | aXNpZ24uY29tL3ZzbG9nby5naWYwHQYDVR0OBBYEFH/TZafC3ey78DAJ80M5+gKv 22 | MzEzMA0GCSqGSIb3DQEBBQUAA4IBAQCTJEowX2LP2BqYLz3q3JktvXf2pXkiOOzE 23 | p6B4Eq1iDkVwZMXnl2YtmAl+X6/WzChl8gGqCBpH3vn5fJJaCGkgDdk+bW48DW7Y 24 | 5gaRQBi5+MHt39tBquCWIMnNZBU4gcmU7qKEKQsTb47bDN0lAtukixlE0kF6BWlK 25 | WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ 26 | 4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N 27 | hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq 28 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /components/oap-common/c_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * c_utils.c 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | 24 | 25 | 26 | #include 27 | 28 | #include "c_list.h" 29 | 30 | /** 31 | * A list is an ordered set of entries. We have the following primitives: 32 | * * list_create() - Create an empty list. The return is the list pointer. 33 | * * list_delete() - Delete the list and optionally free all its entries. 34 | * * list_first() - Return the first item in the list. 35 | * * list_insert() - Add an item to the end of the list. 36 | * * list_insert_after() - Add an item to the list after a given entry. 37 | * * list_insert_before() - Add an item to the list before a given entry. 38 | * * list_next() - Get the next item in the list. 39 | * * list_remove() - Remove a specific item from the list. 40 | * * list_removeByValue() - Find the first element in the list with a matching value and remove it. 41 | */ 42 | 43 | /** 44 | * Create a new list. 45 | */ 46 | list_t *list_createList() { 47 | list_t *pList = malloc(sizeof(list_t)); 48 | pList->next = NULL; 49 | pList->prev = NULL; 50 | pList->value = NULL; 51 | return pList; 52 | } // list_createList 53 | 54 | /** 55 | * Delete a list. 56 | */ 57 | void list_deleteList(list_t *pList, int withFree) { 58 | list_t *pNext; 59 | while(pList != NULL) { 60 | pNext = pList->next; 61 | if (withFree) { 62 | free(pList->value); 63 | } 64 | free(pList); 65 | pList = pNext; 66 | } 67 | } // list_deleteList 68 | 69 | void list_deleteListAndValues(list_t *pList, node_value_predicate disposer) { 70 | list_t *pNext; 71 | while(pList != NULL) { 72 | pNext = pList->next; 73 | if (pList->value) { 74 | disposer(pList->value); 75 | } 76 | free(pList); 77 | pList = pNext; 78 | } 79 | } 80 | 81 | /** 82 | * Insert a new item at the end of the list. 83 | *[A] -> [endOLD] ------> [A] -> [endOLD] -> [X] 84 | * 85 | */ 86 | void list_insert(list_t *pList, void *value) { 87 | while(pList->next != NULL) { 88 | pList = pList->next; 89 | } 90 | list_insert_after(pList, value); 91 | } // list_insert 92 | 93 | /** 94 | * [pEntry] -> [B] ------> [pEntry] -> [X] -> [B] 95 | * 96 | */ 97 | void list_insert_after(list_t *pEntry, void *value) { 98 | list_t *pNew = malloc(sizeof(list_t)); 99 | pNew->next = pEntry->next; 100 | pNew->prev = pEntry; 101 | pNew->value = value; 102 | 103 | // Order IS important here. 104 | if (pEntry->next != NULL) { 105 | pEntry->next->prev = pNew; 106 | } 107 | pEntry->next = pNew; 108 | } // list_insert_after 109 | 110 | /** 111 | * [A] -> [pEntry] ------> [A] -> [X] -> [pEntry] 112 | * 113 | */ 114 | void list_insert_before(list_t *pEntry, void *value) { 115 | // Can't insert before the list itself. 116 | if (pEntry->prev == NULL) { 117 | return; 118 | } 119 | list_t *pNew = malloc(sizeof(list_t)); 120 | pNew->next = pEntry; 121 | pNew->prev = pEntry->prev; 122 | pNew->value = value; 123 | 124 | // Order IS important here. 125 | pEntry->prev->next = pNew; 126 | pEntry->prev = pNew; 127 | } // list_insert_before 128 | 129 | /** 130 | * Remove an item from the list. 131 | */ 132 | void list_remove(list_t *pList, list_t *pEntry, int withFree) { 133 | while(pList != NULL && pList->next != pEntry) { 134 | pList = pList->next; 135 | } 136 | if (pList == NULL) { 137 | return; 138 | } 139 | pList->next = pEntry->next; 140 | if (pEntry->next != NULL) { 141 | pEntry->next->prev = pList; 142 | } 143 | if (withFree) { 144 | free(pEntry->value); 145 | } 146 | free(pEntry); 147 | } // list_delete 148 | 149 | /** 150 | * Delete a list entry by value. 151 | */ 152 | void list_removeByValue(list_t *pList, void *value, int withFree) { 153 | list_t *pNext = pList->next; 154 | while(pNext != NULL) { 155 | if (pNext->value == value) { 156 | list_remove(pList, pNext, withFree); 157 | return; 158 | } 159 | } // End while 160 | } // list_deleteByValue 161 | 162 | /** 163 | * Find a list node with given value 164 | */ 165 | list_t *list_find(list_t *pList, node_value_predicate predicate) { 166 | list_t *pNext = pList->next; 167 | while(pNext != NULL && !predicate(pNext->value)) { 168 | pNext = pNext->next; 169 | } 170 | return pNext; 171 | } 172 | 173 | /** 174 | * Get the next item in a list. 175 | */ 176 | list_t *list_next(list_t *pList) { 177 | if (pList == NULL) { 178 | return NULL; 179 | } 180 | return (pList->next); 181 | } // list_next 182 | 183 | 184 | list_t *list_first(list_t *pList) { 185 | return pList->next; 186 | } // list_first 187 | 188 | void *list_get_value(list_t *pList) { 189 | return pList->value; 190 | } 191 | -------------------------------------------------------------------------------- /components/oap-common/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | COMPONENT_EMBED_TXTFILES := default_config.json -------------------------------------------------------------------------------- /components/oap-common/default_config.json: -------------------------------------------------------------------------------- 1 | { 2 | "wifi": { 3 | "ssid": "", 4 | "password": "", 5 | "ip": "", 6 | "gw": "", 7 | "netmask": "" 8 | }, 9 | "thingspeak": { 10 | "enabled": 0, 11 | "apikey": "" 12 | }, 13 | "awsiot" : { 14 | "enabled": 0, 15 | "endpoint" : "a32on3oilq3poc.iot.eu-west-1.amazonaws.com", 16 | "port" : 8443 17 | }, 18 | "ota" : { 19 | "interval" : 3600 20 | }, 21 | "sensor" : { 22 | "config" : { 23 | "indoor" : 0, 24 | "led" : 1, 25 | "fan" : 1, 26 | "heater" : 1, 27 | "measTime" : 60, 28 | "warmUpTime": 30, 29 | "measInterval": 300, 30 | "test" : 0, 31 | "measStrategy": 0 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /components/oap-common/include/c_list.h: -------------------------------------------------------------------------------- 1 | /* 2 | * c_utils.h 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OAP_COMMON_INCLUDE_C_UTILS_H_ 24 | #define COMPONENTS_OAP_COMMON_INCLUDE_C_UTILS_H_ 25 | 26 | 27 | /* 28 | * c_utils.h 29 | * 30 | * Created on: Nov 15, 2016 31 | * Author: kolban 32 | */ 33 | 34 | typedef struct _list_t { 35 | void *value; 36 | struct _list_t *next; 37 | struct _list_t *prev; 38 | } list_t; 39 | 40 | //typedef int(*node_value_comparator)(void* a, void* b); 41 | typedef int(*node_value_predicate)(void* data); 42 | 43 | list_t *list_createList(); 44 | void list_deleteList(list_t *pList, int withFree); 45 | void list_deleteListAndValues(list_t *pList, node_value_predicate disposer); 46 | void list_insert(list_t *pList, void *value); 47 | void list_remove(list_t *pList, list_t *pEntry, int withFree); 48 | list_t *list_next(list_t *pList); 49 | void list_removeByValue(list_t *pList, void *value, int withFree); 50 | list_t *list_first(list_t *pList); 51 | void list_insert_after(list_t *pEntry, void *value); 52 | void list_insert_before(list_t *pEntry, void *value); 53 | void *list_get_value(list_t *pList); 54 | list_t *list_find(list_t *pList, node_value_predicate predicate); 55 | 56 | 57 | #endif /* COMPONENTS_OAP_COMMON_INCLUDE_C_UTILS_H_ */ 58 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h 3 | * 4 | * Created on: Feb 9, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_COMMON_COMMON_H_ 24 | #define MAIN_COMMON_COMMON_H_ 25 | 26 | #include "oap_version.h" 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include "c_list.h" 33 | #include "esp_err.h" 34 | #include "esp_log.h" 35 | #include "freertos/FreeRTOS.h" 36 | 37 | //to silence eclipse errors 38 | typedef unsigned short uint16_t; 39 | 40 | 41 | 42 | #define DEFAULT_TASK_PRIORITY (10) 43 | 44 | int is_reboot_in_progress(); 45 | void oap_reboot(char* cause); 46 | 47 | long oap_epoch_sec(); 48 | long oap_epoch_sec_valid(); 49 | 50 | //from esp-arduino 51 | 52 | /** 53 | * creates a new string terminated with 0 from passed data. 54 | * free it after use. 55 | */ 56 | char* str_make(void* data, int len); 57 | 58 | /* 59 | * allocates mem and copies src->dest 60 | */ 61 | char* str_dup(char* src); 62 | 63 | //#define ESP_REG(addr) *((volatile uint32_t *)(addr)) 64 | #define NOP() asm volatile ("nop") 65 | 66 | uint32_t micros(); 67 | uint32_t millis(); 68 | void delay(uint32_t); 69 | void delayMicroseconds(uint32_t us); 70 | 71 | #endif /* MAIN_COMMON_COMMON_H_ */ 72 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_data.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_data.h 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_H_ 24 | #define COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_H_ 25 | 26 | #include "oap_data_pm.h" 27 | #include "oap_data_env.h" 28 | 29 | typedef struct { 30 | pm_data_t* pm; 31 | pm_data_t* pm_aux; 32 | env_data_t* env; 33 | env_data_t* env_int; 34 | long int local_time; 35 | } oap_measurement_t; 36 | 37 | typedef struct { 38 | int led; 39 | int heater; 40 | int fan; 41 | 42 | int indoor; 43 | int warm_up_time; 44 | int meas_time; 45 | int meas_interval; 46 | int meas_strategy; //interval, continuos, etc 47 | int test; 48 | } oap_sensor_config_t; 49 | 50 | 51 | #endif /* COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_H_ */ 52 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_data_env.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_data_env.h 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_ENV_H_ 24 | #define COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_ENV_H_ 25 | 26 | typedef struct { 27 | double temp; 28 | double pressure; 29 | double humidity; 30 | uint8_t sensor_idx; 31 | } env_data_t; 32 | 33 | #endif /* COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_ENV_H_ */ 34 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_data_pm.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_data_pm.h 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_PM_H_ 24 | #define COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_PM_H_ 25 | 26 | typedef struct { 27 | uint16_t pm1_0; 28 | uint16_t pm2_5; 29 | uint16_t pm10; 30 | uint8_t sensor_idx; 31 | } pm_data_t; 32 | 33 | typedef void(*pm_data_callback_f)(pm_data_t*); 34 | 35 | #endif /* COMPONENTS_OAP_COMMON_INCLUDE_OAP_DATA_PM_H_ */ 36 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_debug.h 3 | * 4 | * Created on: Mar 13, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | typedef struct heap_log { 24 | size_t heap; 25 | char* tag; 26 | struct heap_log* next; 27 | } heap_log; 28 | 29 | void heap_log_print(heap_log* log, heap_log* prev); 30 | heap_log* heap_log_take(heap_log* log, const char* msg); 31 | void heap_log_free(heap_log* log); 32 | 33 | size_t avg_free_heap_size(); 34 | 35 | void log_task_stack(const char* task); 36 | void log_heap_size(const char* msg); 37 | void reduce_heap_size_to(size_t size); 38 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_publisher.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_publisher.h 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OAP_COMMON_INCLUDE_OAP_PUBLISHER_H_ 24 | #define COMPONENTS_OAP_COMMON_INCLUDE_OAP_PUBLISHER_H_ 25 | 26 | #include "cJSON.h" 27 | #include "oap_data.h" 28 | #include "esp_err.h" 29 | 30 | typedef esp_err_t(*oap_publisher_configure_f)(cJSON* config); 31 | typedef esp_err_t(*oap_publisher_publish_f)(oap_measurement_t* meas, oap_sensor_config_t* sensor_config); 32 | 33 | typedef struct { 34 | char* name; 35 | oap_publisher_configure_f configure; 36 | oap_publisher_publish_f publish; 37 | } oap_publisher_t; 38 | 39 | #endif /* COMPONENTS_OAP_COMMON_INCLUDE_OAP_PUBLISHER_H_ */ 40 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_storage.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_storage.h 3 | * 4 | * Created on: Feb 11, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OAP_COMMON_INCLUDE_OAP_STORAGE_H_ 24 | #define COMPONENTS_OAP_COMMON_INCLUDE_OAP_STORAGE_H_ 25 | 26 | #include 27 | #include "cJSON.h" 28 | 29 | 30 | /** 31 | * @brief initialise storage and config 32 | */ 33 | void storage_init(); 34 | 35 | /** 36 | * @brief return config for given submodule 37 | * 38 | * @param[in] module name of a submodule, e.g. 'wifi' or NULL to retrieve full config tree 39 | * 40 | * @return config JSON. DO NOT free or modify the result, it is a singleton! 41 | */ 42 | cJSON* storage_get_config(const char* module); 43 | 44 | 45 | /** 46 | * @brief returns config json as a string 47 | * 48 | * sensitive data (wifi password) is replaced with constant string 49 | * 50 | * @return config json. free it after use! 51 | */ 52 | cJSON* storage_get_config_to_update(); 53 | 54 | 55 | /** 56 | * @bried updates json config 57 | * 58 | * sensitive data (wifi password) that has not been changed is being replaced with proper values. 59 | * 60 | * @param[in] json config 61 | */ 62 | void storage_update_config(cJSON* config); 63 | 64 | 65 | #endif /* COMPONENTS_OAP_COMMON_INCLUDE_OAP_STORAGE_H_ */ 66 | -------------------------------------------------------------------------------- /components/oap-common/include/oap_version.h: -------------------------------------------------------------------------------- 1 | /* 2 | * version.h 3 | * 4 | * Created on: Sep 7, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_INCLUDE_OAP_VERSION_H_ 24 | #define MAIN_INCLUDE_OAP_VERSION_H_ 25 | 26 | /** 27 | * http://semver.org/ 28 | * 29 | * Given a version number MAJOR.MINOR.PATCH, increment the: 30 | * 31 | * MAJOR version when you make incompatible API changes, 32 | * MINOR version when you add functionality in a backwards-compatible manner, and 33 | * PATCH version when you make backwards-compatible bug fixes. 34 | */ 35 | 36 | #include 37 | #include "esp_err.h" 38 | 39 | #define OAP_VER_MAJOR 1 40 | #define OAP_VER_MINOR 2 41 | #define OAP_VER_PATCH 0 42 | 43 | typedef struct { 44 | uint8_t major; 45 | uint8_t minor; 46 | uint8_t patch; 47 | } oap_version_t; 48 | 49 | oap_version_t oap_version(); 50 | char* oap_version_str(); 51 | char* oap_version_format(oap_version_t ver); 52 | esp_err_t oap_version_parse(char* str, oap_version_t* ver); 53 | unsigned long oap_version_num(oap_version_t ver); 54 | 55 | #endif /* MAIN_INCLUDE_OAP_VERSION_H_ */ 56 | -------------------------------------------------------------------------------- /components/oap-common/oap_common.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_common.c 3 | * 4 | * Created on: Feb 22, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | #include "freertos/FreeRTOS.h" 27 | #include 28 | #include "oap_common.h" 29 | #include "esp_attr.h" 30 | #include "esp_log.h" 31 | #include "esp_system.h" 32 | #include "freertos/task.h" 33 | 34 | static const long FEB22_2017 = 1487795557; 35 | 36 | static int _reboot_in_progress = 0; 37 | int is_reboot_in_progress() { 38 | return _reboot_in_progress; 39 | } 40 | void oap_reboot(char* cause) { 41 | ESP_LOGW("oap", "REBOOT ON DEMAND (%s)", cause); 42 | _reboot_in_progress = 1; 43 | esp_restart(); 44 | } 45 | 46 | long oap_epoch_sec() { 47 | struct timeval tv_start; 48 | gettimeofday(&tv_start, NULL); 49 | return tv_start.tv_sec; 50 | } 51 | 52 | long oap_epoch_sec_valid() { 53 | long epoch = oap_epoch_sec(); 54 | return epoch > FEB22_2017 ? epoch : 0; 55 | } 56 | 57 | char* str_make(void* data, int len) { 58 | char* str = malloc(len+1); 59 | memcpy(str, data, len); 60 | str[len] = 0; 61 | return str; 62 | } 63 | 64 | char* str_dup(char* src) { 65 | char* dest = malloc(strlen(src)+1); 66 | strcpy(dest, src); 67 | return dest; 68 | } 69 | 70 | void yield() 71 | { 72 | vPortYield(); 73 | } 74 | 75 | uint32_t IRAM_ATTR micros() 76 | { 77 | uint32_t ccount; 78 | __asm__ __volatile__ ( "rsr %0, ccount" : "=a" (ccount) ); 79 | return ccount / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ; 80 | } 81 | 82 | uint32_t IRAM_ATTR millis() 83 | { 84 | return xTaskGetTickCount() * portTICK_PERIOD_MS; 85 | } 86 | 87 | void delay(uint32_t ms) 88 | { 89 | vTaskDelay(ms / portTICK_PERIOD_MS); 90 | } 91 | 92 | void IRAM_ATTR delayMicroseconds(uint32_t us) 93 | { 94 | uint32_t m = micros(); 95 | if(us){ 96 | uint32_t e = (m + us) % ((0xFFFFFFFF / CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) + 1); 97 | if(m > e){ //overflow 98 | while(micros() > e){ 99 | NOP(); 100 | } 101 | } 102 | while(micros() < e){ 103 | NOP(); 104 | } 105 | } 106 | } 107 | 108 | 109 | -------------------------------------------------------------------------------- /components/oap-common/oap_debug.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_debug.c 3 | * 4 | * Created on: Mar 13, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include 24 | #include 25 | #include "freertos/FreeRTOS.h" 26 | #include 27 | #include "oap_debug.h" 28 | #include "esp_attr.h" 29 | #include "esp_log.h" 30 | #include "freertos/task.h" 31 | 32 | #define TAG "mem" 33 | /** 34 | * this method is surprisingly stack heavy - it takes ~ 1000 bytes. 35 | * before using it, adjust task stack accordingly. 36 | */ 37 | void log_task_stack(const char* task) { 38 | //uxTaskGetStackHighWaterMark is marked as UNTESTED 39 | #if !CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION 40 | ESP_LOGD(TAG, "stack min %d (task %s)", uxTaskGetStackHighWaterMark( NULL ), task); 41 | #endif 42 | } 43 | 44 | /** 45 | * current free heap is not very useful because it changes dynamically with multiple tasks running in parallel. 46 | * to detect any leaks, we use a time window and choose the max value as real 'free heap' 47 | */ 48 | #define SAMPLES 10 49 | static size_t heap_samples[SAMPLES] = {.0}; 50 | uint8_t sample_idx = 0; 51 | 52 | size_t avg_free_heap_size() { 53 | size_t max = 0; 54 | for (int i = 0; i < SAMPLES; i++) { 55 | if (heap_samples[i] > max) max = heap_samples[i]; 56 | } 57 | return max; 58 | } 59 | 60 | void log_heap_size(const char* msg) { 61 | size_t free_heap = xPortGetFreeHeapSize(); 62 | if (heap_samples[sample_idx%SAMPLES] == 0) heap_samples[sample_idx%SAMPLES] = free_heap; 63 | 64 | ESP_LOGD(TAG, "heap min %d avg %d (%s)", 65 | xPortGetMinimumEverFreeHeapSize(), 66 | avg_free_heap_size(), 67 | msg); 68 | heap_samples[sample_idx%SAMPLES] = free_heap; 69 | sample_idx++; 70 | } 71 | 72 | static void* dummy; 73 | void reduce_heap_size_to(size_t size) { 74 | size_t reduce_by = xPortGetFreeHeapSize() - size; 75 | if (reduce_by > 0) { 76 | ESP_LOGE(TAG, "********************** REDUCE HEAP BY %d TO %d bytes !!!!!!!!!!!", reduce_by, size); 77 | do { 78 | size_t block = reduce_by > 10000 ? 10000 : reduce_by; 79 | reduce_by-=block; 80 | dummy = malloc(block); 81 | if (!dummy) { 82 | ESP_LOGE(TAG, "FAILED TO ALLOCATE!"); 83 | } 84 | } while (reduce_by > 0); 85 | } 86 | } 87 | 88 | static int heap_log_count = 0; 89 | 90 | /* 91 | | 100 | 92 | | -1 | 93 | 99 | | 100 (c=1) 94 | | -10 | 95 | | -1 | 96 | 88 | | 90 (c=2) 97 | */ 98 | 99 | void heap_log_list(heap_log* log) { 100 | heap_log* prev = NULL; 101 | int c = 0; 102 | while (log) { 103 | c++; 104 | heap_log_print(log, prev); 105 | prev = log; 106 | log = log->next; 107 | } 108 | } 109 | 110 | void heap_log_print(heap_log* log, heap_log* prev) { 111 | size_t comp_heap = log->heap + heap_log_count * sizeof(heap_log); 112 | if (prev == NULL) { 113 | ESP_LOGD("debug", "----------> heap %25s: %d", log->tag, comp_heap); 114 | } else { 115 | size_t diff_heap = log->heap - prev->heap + sizeof(heap_log); 116 | ESP_LOGD("debug", "----------> heap %25s: %d \t (%d)", log->tag, comp_heap, diff_heap); 117 | } 118 | } 119 | 120 | heap_log* heap_log_take(heap_log* log, const char* msg) { 121 | heap_log* new_log = malloc(sizeof(heap_log)); 122 | heap_log_count++; 123 | new_log->tag = strdup(msg); 124 | new_log->next = NULL; 125 | 126 | //find tail 127 | if (log != NULL) { 128 | while (log->next) { 129 | log = log->next; 130 | } 131 | log->next = new_log; 132 | } 133 | 134 | new_log->heap = xPortGetFreeHeapSize(); 135 | //heap_log_print(new_log, log); 136 | return new_log; 137 | } 138 | 139 | void heap_log_free(heap_log* log) { 140 | if (log) { 141 | size_t initial_heap = log->heap; 142 | 143 | heap_log_list(log); 144 | heap_log* next; 145 | do { 146 | next = log->next; 147 | free(log->tag); 148 | free(log); 149 | heap_log_count--; 150 | log = next; 151 | } while (log); 152 | 153 | 154 | ESP_LOGD("debug", "----------> leaked : %d", xPortGetFreeHeapSize() - initial_heap); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /components/oap-common/oap_version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_version.c 3 | * 4 | * Created on: Sep 7, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "oap_version.h" 24 | #include 25 | #include 26 | #include "esp_err.h" 27 | 28 | static oap_version_t _oap_version = { .major = OAP_VER_MAJOR, .minor = OAP_VER_MINOR, .patch = OAP_VER_PATCH }; 29 | static char* _oap_version_str = NULL; 30 | 31 | static const char* VER_FORMAT="%d.%d.%d"; 32 | 33 | char* oap_version_format(oap_version_t ver) { 34 | char* str = malloc(snprintf( NULL, 0, VER_FORMAT, ver.major, ver.minor, ver.patch)+1); 35 | sprintf(str, VER_FORMAT, ver.major, ver.minor, ver.patch); 36 | return str; 37 | } 38 | 39 | oap_version_t oap_version() { 40 | return _oap_version; 41 | } 42 | 43 | char* oap_version_str() { 44 | if (!_oap_version_str) { 45 | _oap_version_str = oap_version_format(_oap_version); 46 | } 47 | return _oap_version_str; 48 | } 49 | 50 | unsigned long oap_version_num(oap_version_t ver) { 51 | return 10000 * ver.major + 100 * ver.minor + ver.patch; 52 | } 53 | 54 | esp_err_t oap_version_parse(char* str, oap_version_t* ver) 55 | { 56 | int i = 0; 57 | while (str[i] != 0 && str[i] != '.') i++; 58 | if (str[i] != '.') return ESP_FAIL; 59 | int major = atoi(str); 60 | i++; 61 | int minor = atoi(str+i); 62 | while (str[i] != 0 && str[i] != '.') i++; 63 | if (str[i] != '.') return ESP_FAIL; 64 | i++; 65 | int patch = atoi(str+i); 66 | 67 | ver->major = major; 68 | ver->minor = minor; 69 | ver->patch = patch; 70 | 71 | return ESP_OK; 72 | } 73 | 74 | 75 | -------------------------------------------------------------------------------- /components/oap-common/test/.gitignore: -------------------------------------------------------------------------------- 1 | test_wifi.h -------------------------------------------------------------------------------- /components/oap-common/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-common/test/include/oap_test.h: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_test.h 3 | * 4 | * Created on: Sep 11, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OAP_COMMON_TEST_INCLUDE_OAP_TEST_H_ 24 | #define COMPONENTS_OAP_COMMON_TEST_INCLUDE_OAP_TEST_H_ 25 | 26 | #include "unity.h" 27 | #include "esp_log.h" 28 | #include "freertos/FreeRTOS.h" 29 | #include "bootwifi.h" 30 | 31 | #define TEST "TEST" 32 | 33 | void test_reset_hw(); 34 | /** 35 | * init wifi, do not wait for IP 36 | */ 37 | void test_init_wifi(); 38 | 39 | /** 40 | * init wifi and wait for IP 41 | */ 42 | void test_require_wifi(); 43 | 44 | void test_require_wifi_with(wifi_state_callback_f callback); 45 | 46 | void test_require_ap(); 47 | 48 | void test_require_ap_with(wifi_state_callback_f callback); 49 | 50 | typedef struct { 51 | uint32_t started; 52 | uint32_t wait_for; 53 | } test_timer_t; 54 | 55 | int test_timeout(test_timer_t* t); 56 | 57 | void test_delay(uint32_t ms); 58 | 59 | #endif /* COMPONENTS_OAP_COMMON_TEST_INCLUDE_OAP_TEST_H_ */ 60 | -------------------------------------------------------------------------------- /components/oap-common/test/oap_test.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_test.c 3 | * 4 | * Created on: Sep 11, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "esp_log.h" 24 | #include "oap_test.h" 25 | #include "bootwifi.h" 26 | #include "test_wifi.h" 27 | #include "unity.h" 28 | 29 | #include "esp_attr.h" 30 | #include "esp_log.h" 31 | #include "esp_system.h" 32 | #include 33 | 34 | static const char* TAG = "test"; 35 | 36 | extern oc_wifi_t oap_wifi_config; 37 | 38 | void test_require_wifi() { 39 | test_require_wifi_with(NULL); 40 | } 41 | 42 | void test_require_wifi_with(wifi_state_callback_f wifi_state_callback) { 43 | memset(&oap_wifi_config, 0, sizeof(oap_wifi_config)); 44 | strcpy(oap_wifi_config.ssid, OAP_TEST_WIFI_SSID); 45 | strcpy(oap_wifi_config.password,OAP_TEST_WIFI_PASSWORD); 46 | oap_wifi_config.callback = wifi_state_callback; 47 | wifi_boot(); 48 | TEST_ESP_OK(wifi_connected_wait_for(10000)); 49 | ESP_LOGI(TAG, "connected sta"); 50 | } 51 | 52 | void test_require_ap() { 53 | test_require_ap_with(NULL); 54 | } 55 | 56 | void test_require_ap_with(wifi_state_callback_f wifi_state_callback) { 57 | memset(&oap_wifi_config, 0, sizeof(oap_wifi_config)); 58 | oap_wifi_config.ap_mode=1; 59 | oap_wifi_config.callback = wifi_state_callback; 60 | wifi_boot(); 61 | TEST_ESP_OK(wifi_ap_started_wait_for(10000)); 62 | ESP_LOGI(TAG, "connected ap"); 63 | } 64 | 65 | static uint32_t IRAM_ATTR time_now() 66 | { 67 | return xTaskGetTickCount() * portTICK_PERIOD_MS; 68 | } 69 | 70 | int test_timeout(test_timer_t* t) { 71 | if (t->started <= 0) t->started = time_now(); 72 | return time_now() - t->started > t->wait_for; 73 | } 74 | 75 | void test_delay(uint32_t ms) 76 | { 77 | vTaskDelay(ms / portTICK_PERIOD_MS); 78 | } 79 | 80 | static void configure_gpio(uint8_t gpio) { 81 | if (gpio > 0) { 82 | ESP_LOGD(TAG, "configure pin %d as output", gpio); 83 | gpio_pad_select_gpio(gpio); 84 | ESP_ERROR_CHECK(gpio_set_direction(gpio, GPIO_MODE_OUTPUT)); 85 | ESP_ERROR_CHECK(gpio_set_pull_mode(gpio, GPIO_PULLDOWN_ONLY)); 86 | } 87 | } 88 | 89 | void test_reset_hw() { 90 | ESP_LOGI(TAG,"reset peripherals"); 91 | configure_gpio(GPIO_NUM_10); //disable pm1 92 | configure_gpio(GPIO_NUM_2); //disable pm2 93 | } 94 | -------------------------------------------------------------------------------- /components/oap-common/test/sandbox.c: -------------------------------------------------------------------------------- 1 | /* 2 | * sandbox.c 3 | * 4 | * Created on: Sep 12, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "unity.h" 29 | #include "nvs.h" 30 | #include "nvs_flash.h" 31 | #include "esp_partition.h" 32 | #include "esp_log.h" 33 | #include 34 | #include "esp_system.h" 35 | 36 | /* 37 | typedef struct { 38 | uint8_t num; 39 | char* str; 40 | } sample_struct; 41 | 42 | static const char* TAG = "test"; 43 | 44 | void* modify_struct_by_value(sample_struct ss) { 45 | ss.num++; 46 | ss.str = "modified!"; 47 | //warning: function returns address of local variable [-Wreturn-local-addr] 48 | return &ss; 49 | } 50 | 51 | void modify_struct_by_ref(sample_struct* ss) { 52 | ss->num++; 53 | ss->str = "modified!"; //what happens with assigned string? tricky - if it was a const we cannot release it. prefer immutable structs! 54 | } 55 | 56 | TEST_CASE("structs","sandbox") { 57 | sample_struct ss = { 58 | .num = 1, 59 | .str = "hello" 60 | }; 61 | 62 | void* ssp = modify_struct_by_value(ss); 63 | 64 | TEST_ASSERT_EQUAL_STRING("hello", ss.str); 65 | TEST_ASSERT_EQUAL_INT(1, ss.num); 66 | TEST_ASSERT_EQUAL_INT32(0, ssp); 67 | 68 | char* str = ss.str; 69 | modify_struct_by_ref(&ss); 70 | TEST_ASSERT_EQUAL_STRING("modified!", ss.str); 71 | TEST_ASSERT_EQUAL_INT(2, ss.num); 72 | 73 | ESP_LOGI(TAG, "old str:%s", str); 74 | //str[0] = '!'; //error (const allocation) 75 | //free(str); //error free() target pointer is outside heap areas 76 | }*/ 77 | 78 | /* 79 | TEST_CASE("mac", "sandbox") { 80 | uint8_t mac[6]; 81 | esp_efuse_mac_get_default(mac); 82 | ESP_LOGD("TST", "MAC= %02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); 83 | } 84 | */ 85 | -------------------------------------------------------------------------------- /components/oap-common/test/test_oap_version.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_test.c 3 | * 4 | * Created on: Sep 11, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "unity.h" 29 | #include "nvs.h" 30 | #include "nvs_flash.h" 31 | #include "esp_partition.h" 32 | #include "esp_log.h" 33 | #include 34 | #include "oap_version.h" 35 | 36 | static void parse_format_verify(char* input, char* output) { 37 | oap_version_t ver; 38 | char* str; 39 | 40 | memset(&ver, 0, sizeof(ver)); 41 | TEST_ESP_OK(oap_version_parse(input, &ver)); 42 | str = oap_version_format(ver); 43 | TEST_ASSERT_EQUAL_STRING(output, str); 44 | free(str); 45 | } 46 | 47 | TEST_CASE("parse and format version","oap_version") { 48 | parse_format_verify("1.2.3","1.2.3"); 49 | parse_format_verify("0.4.0","0.4.0"); 50 | parse_format_verify("012.034.056","12.34.56"); 51 | } 52 | 53 | TEST_CASE("version to num","oap_version") { 54 | oap_version_t v1 = { 55 | .major = 12, 56 | .minor = 34, 57 | .patch = 56, 58 | 59 | }; 60 | TEST_ASSERT_EQUAL_UINT32(123456, oap_version_num(v1)); 61 | 62 | oap_version_t v2 = { 63 | .major = 0, 64 | .minor = 4, 65 | .patch = 0, 66 | 67 | }; 68 | TEST_ASSERT_EQUAL_UINT32(400, oap_version_num(v2)); 69 | } 70 | -------------------------------------------------------------------------------- /components/oap-http/README.md: -------------------------------------------------------------------------------- 1 | # Lightweight HTTP client for ESP32 2 | ## Example 3 | 4 | ```cpp 5 | int download_callback(request_t *req, char *data, int len) 6 | { 7 | req_list_t *found = req->response->header; 8 | while(found->next != NULL) { 9 | found = found->next; 10 | ESP_LOGI(TAG,"Response header %s:%s", (char*)found->key, (char*)found->value); 11 | } 12 | //or 13 | found = req_list_get_key(req->response->header, "Content-Length"); 14 | if(found) { 15 | ESP_LOGI(TAG,"Get header %s:%s", (char*)found->key, (char*)found->value); 16 | } 17 | ESP_LOGI(TAG,"%s", data); 18 | return 0; 19 | } 20 | static void request_task(void *pvParameters) 21 | { 22 | request_t *req; 23 | int status; 24 | xEventGroupWaitBits(wifi_event_group, CONNECTED_BIT, false, true, portMAX_DELAY); 25 | ESP_LOGI(TAG, "Connected to AP, freemem=%d",esp_get_free_heap_size()); 26 | // vTaskDelay(1000/portTICK_RATE_MS); 27 | req = req_new("http://httpbin.org/post"); 28 | //or 29 | //request *req = req_new("https://google.com"); //for SSL 30 | req_setopt(req, REQ_SET_METHOD, "POST"); 31 | req_setopt(req, REQ_SET_POSTFIELDS, "test=data&test2=data2"); 32 | req_setopt(req, REQ_FUNC_DOWNLOAD_CB, download_callback); 33 | status = req_perform(req); 34 | req_clean(req); 35 | vTaskDelete(NULL); 36 | } 37 | 38 | ``` 39 | 40 | ## Usage 41 | - Create ESP-IDF application https://github.com/espressif/esp-idf-template 42 | - Clone `git submodule add https://github.com/tuanpmt/esp-request components/esp-request` 43 | - Example `esp-request` application: https://github.com/tuanpmt/esp-request-app 44 | - OTA application using `esp-request`: https://github.com/tuanpmt/esp32-fota 45 | 46 | ## API 47 | 48 | ### Function 49 | - `req_new` 50 | - `req_setopt` 51 | - `req_clean` 52 | 53 | ### Options for `req_setopt` 54 | - REQ_SET_METHOD - `req_setopt(req, REQ_SET_METHOD, "GET");//or POST/PUT/DELETE` 55 | - REQ_SET_HEADER - `req_setopt(req, REQ_SET_HEADER, "HeaderKey: HeaderValue");` 56 | - REQ_SET_HOST - `req_setopt(req, REQ_SET_HOST, "google.com"); //or 192.168.0.1` 57 | - REQ_SET_PORT - `req_setopt(req, REQ_SET_PORT, "80");//must be string` 58 | - REQ_SET_PATH - `req_setopt(req, REQ_SET_PATH, "/path");` 59 | - REQ_SET_SECURITY 60 | - REQ_SET_URI - `req_setopt(req, REQ_SET_URI, "http://uri.com"); //will replace host, port, path, security and Auth if present` 61 | - REQ_SET_DATAFIELDS 62 | - REQ_SET_UPLOAD_LEN - Not effect for now 63 | - REQ_FUNC_DOWNLOAD_CB - `req_setopt(req, REQ_FUNC_DOWNLOAD_CB, download_callback);` 64 | - REQ_FUNC_UPLOAD_CB 65 | - REQ_REDIRECT_FOLLOW - `req_setopt(req, REQ_REDIRECT_FOLLOW, "true"); //or "false"` 66 | 67 | ### URI format 68 | - Follow this: https://en.wikipedia.org/wiki/Uniform_Resource_Identifier 69 | 70 | ## Todo 71 | - [x] Support URI parser 72 | - [x] Follow redirect 73 | - [x] Support SSL 74 | - [x] Support Set POST Fields (simple) 75 | - [ ] Support Basic Auth 76 | - [ ] Support Upload multipart 77 | - [ ] Support Cookie 78 | 79 | ## Known Issues 80 | - ~~Memory leak~~ 81 | - Uri parse need more work 82 | 83 | ## Authors 84 | - [Tuan PM](https://twitter.com/tuanpmt) 85 | -------------------------------------------------------------------------------- /components/oap-http/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | 6 | 7 | -------------------------------------------------------------------------------- /components/oap-http/include/esp_request.h: -------------------------------------------------------------------------------- 1 | #ifndef _ESP_REQUEST_H_ 2 | #define _ESP_REQUEST_H_ 3 | #include "req_list.h" 4 | #include "uri_parser.h" 5 | #include "lwip/sockets.h" 6 | #include "lwip/netdb.h" 7 | 8 | #include "mbedtls/ssl.h" 9 | #include "mbedtls/entropy.h" 10 | #include "mbedtls/ctr_drbg.h" 11 | 12 | #define HTTP_HEADER_CONTENT_TYPE_JSON "Content-Type: application/json" 13 | #define HTTP_HEADER_CONNECTION_CLOSE "Connection: close" 14 | #define HTTP_POST "POST" 15 | #define HTTP_GET "GET" 16 | 17 | typedef enum { 18 | REQ_SET_METHOD = 0x01, 19 | REQ_SET_HEADER, 20 | REQ_SET_HOST, 21 | REQ_SET_PORT, 22 | REQ_SET_PATH, 23 | REQ_SET_URI, 24 | REQ_SET_SECURITY, 25 | REQ_SET_POSTFIELDS, 26 | REQ_SET_DATAFIELDS, 27 | REQ_SET_UPLOAD_LEN, 28 | REQ_FUNC_DOWNLOAD_CB, 29 | REQ_FUNC_UPLOAD_CB, 30 | REQ_REDIRECT_FOLLOW 31 | } REQ_OPTS; 32 | 33 | typedef struct response_t { 34 | req_list_t *header; 35 | int status_code; 36 | int len; 37 | } response_t; 38 | 39 | typedef struct { 40 | size_t buffer_length; 41 | int bytes_read; 42 | int bytes_write; 43 | int bytes_total; 44 | char *data; 45 | int at_eof; 46 | } req_buffer_t; 47 | 48 | 49 | typedef struct { 50 | mbedtls_ssl_context ssl_ctx; 51 | mbedtls_ssl_config ssl_conf; 52 | mbedtls_ctr_drbg_context drbg_ctx; 53 | mbedtls_entropy_context entropy_ctx; 54 | } req_ssl; 55 | 56 | typedef struct request_t { 57 | req_list_t *opt; 58 | req_list_t *header; 59 | 60 | req_buffer_t *buffer; 61 | size_t buffer_size; 62 | void *context; 63 | int socket; 64 | int (*_connect)(struct request_t *req); 65 | int (*_read)(struct request_t *req, char *buffer, int len); 66 | int (*_write)(struct request_t *req, char *buffer, int len); 67 | int (*_close)(struct request_t *req); 68 | int (*upload_callback)(struct request_t *req, void *buffer, int len); 69 | int (*download_callback)(struct request_t *req, void *buffer, int len); 70 | response_t *response; 71 | 72 | //mbedtls 73 | req_ssl* ssl; 74 | mbedtls_x509_crt* ca_cert; 75 | mbedtls_x509_crt* client_cert; 76 | mbedtls_pk_context* client_key; 77 | 78 | //meta 79 | void* meta; 80 | 81 | } request_t; 82 | 83 | typedef int (*download_cb)(request_t *req, void *buffer, int len); 84 | typedef int (*upload_cb)(request_t *req, void *buffer, int len); 85 | 86 | 87 | request_t *req_new(const char *url); 88 | request_t *req_new_with_buf(const char *uri, size_t buffer_size); 89 | void req_setopt(request_t *req, REQ_OPTS opt, void* data); 90 | void req_clean(request_t *req); 91 | int req_perform(request_t *req); 92 | 93 | void req_free_x509_crt(mbedtls_x509_crt* crt); 94 | void req_free_pkey(mbedtls_pk_context* pkey); 95 | mbedtls_x509_crt* req_parse_x509_crt(unsigned char *buf, size_t buflen); 96 | mbedtls_pk_context* req_parse_pkey(unsigned char* buf, size_t buflen); 97 | 98 | #endif 99 | -------------------------------------------------------------------------------- /components/oap-http/include/req_list.h: -------------------------------------------------------------------------------- 1 | #ifndef _LIST_H 2 | #define _LIST_H 3 | 4 | typedef struct req_list_t { 5 | void *key; 6 | void *value; 7 | struct req_list_t *next; 8 | struct req_list_t *prev; 9 | } req_list_t; 10 | 11 | void req_list_add(req_list_t *root, req_list_t *new_tree); 12 | req_list_t *req_list_get_last(req_list_t *root); 13 | req_list_t *req_list_get_first(req_list_t *root); 14 | void req_list_remove(req_list_t *tree); 15 | void req_list_clear(req_list_t *root); 16 | req_list_t *req_list_set_key(req_list_t *root, const char *key, const char *value); 17 | req_list_t *req_list_get_key(req_list_t *root, const char *key); 18 | int req_list_check_key(req_list_t *root, const char *key, const char *value); 19 | req_list_t *req_list_set_from_string(req_list_t *root, const char *data); //data = "key=value" 20 | #endif 21 | -------------------------------------------------------------------------------- /components/oap-http/include/uri_parser.h: -------------------------------------------------------------------------------- 1 | #ifndef _uri_parser_ 2 | #define _uri_parser_ 3 | #ifdef __cplusplus 4 | extern "C" { 5 | #endif 6 | typedef struct { 7 | char *scheme; /* mandatory */ 8 | char *host; /* mandatory */ 9 | char *port; /* optional */ 10 | char *path; /* optional */ 11 | char *query; /* optional */ 12 | char *fragment; /* optional */ 13 | char *username; /* optional */ 14 | char *password; /* optional */ 15 | char *extension; 16 | char *host_ext; 17 | char *_uri; /* private */ 18 | int _uri_len; /* private */ 19 | } parsed_uri_t; 20 | 21 | parsed_uri_t *parse_uri(const char *); 22 | void free_parsed_uri(parsed_uri_t *); 23 | void parse_uri_info(parsed_uri_t *puri); 24 | #ifdef __cplusplus 25 | } 26 | #endif 27 | 28 | #endif /* _uri_parser_ */ 29 | -------------------------------------------------------------------------------- /components/oap-http/req_list.c: -------------------------------------------------------------------------------- 1 | /* 2 | * @2017 3 | * Tuan PM 4 | */ 5 | #include 6 | #include 7 | #include 8 | #include "req_list.h" 9 | #include "esp_log.h" 10 | #define LIST_TAG "LIST" 11 | static char *trimwhitespace(char *str) 12 | { 13 | char *end; 14 | 15 | // Trim leading space 16 | while(isspace((unsigned char)*str)) str++; 17 | 18 | if(*str == 0) // All spaces? 19 | return str; 20 | 21 | // Trim trailing space 22 | end = str + strlen(str) - 1; 23 | while(end > str && isspace((unsigned char)*end)) end--; 24 | 25 | // Write new null terminator 26 | *(end+1) = 0; 27 | 28 | return str; 29 | } 30 | void req_list_add(req_list_t *root, req_list_t *new_tree) 31 | { 32 | req_list_t *last = req_list_get_last(root); 33 | if(last != NULL) { 34 | last->next = new_tree; 35 | new_tree->prev = last; 36 | } 37 | } 38 | req_list_t *req_list_get_last(req_list_t *root) 39 | { 40 | req_list_t *last; 41 | if(root == NULL) 42 | return NULL; 43 | last = root; 44 | while(last->next != NULL) { 45 | last = last->next; 46 | } 47 | return last; 48 | } 49 | req_list_t *req_list_get_first(req_list_t *root) 50 | { 51 | if(root == NULL) 52 | return NULL; 53 | if(root->next == NULL) 54 | return NULL; 55 | // ESP_LOGD(LIST_TAG, "root->next = %x", (int)root->next); 56 | return root->next; 57 | } 58 | void req_list_remove(req_list_t *tree) 59 | { 60 | req_list_t *found = tree; 61 | if (found != NULL) { 62 | if (found->next && found->prev) { 63 | // ESP_LOGD(LIST_TAG, "found->prev->next= %x, found->next->prev=%x", (int)found->prev->next, (int)found->next->prev); 64 | found->prev->next = found->next; 65 | found->next->prev = found->prev; 66 | } else if (found->next) { 67 | // ESP_LOGD(LIST_TAG, "found->next->prev= %x", (int)found->next->prev); 68 | found->next->prev = NULL; 69 | } else if (found->prev) { 70 | // ESP_LOGD(LIST_TAG, "found->prev->next =%x", (int)found->prev->next); 71 | found->prev->next = NULL; 72 | } 73 | free(found->key); 74 | free(found->value); 75 | free(found); 76 | } 77 | } 78 | 79 | void req_list_clear(req_list_t *root) 80 | { 81 | //FIXME: Need to test this function 82 | req_list_t *found; 83 | while((found = req_list_get_first(root)) != NULL) { 84 | // ESP_LOGD(LIST_TAG, "free key=%s, value=%s, found=%x", (char*)found->key, (char*)found->value, (int)found); 85 | req_list_remove(found); 86 | } 87 | } 88 | 89 | req_list_t *req_list_set_key(req_list_t *root, const char *key, const char *value) 90 | { 91 | req_list_t *found; 92 | if(root == NULL) 93 | return NULL; 94 | found = root; 95 | while(found->next != NULL) { 96 | found = found->next; 97 | if (strcasecmp(found->key, key) == 0) { 98 | if (found->value) { 99 | free(found->value); 100 | } 101 | found->value = calloc(1, strlen(value)+1); 102 | strcpy(found->value, value); 103 | return found; 104 | } 105 | } 106 | req_list_t *new_tree = calloc(1, sizeof(req_list_t)); 107 | if (new_tree == NULL) 108 | return NULL; 109 | new_tree->key = calloc(1, strlen(key) + 1); 110 | strcpy(new_tree->key, key); 111 | new_tree->value = calloc(1, strlen(value)+1); 112 | strcpy(new_tree->value, value); 113 | 114 | req_list_add(root, new_tree); 115 | return new_tree; 116 | } 117 | req_list_t *req_list_get_key(req_list_t *root, const char *key) 118 | { 119 | req_list_t *found; 120 | if(root == NULL) 121 | return NULL; 122 | found = root; 123 | while(found->next != NULL) { 124 | found = found->next; 125 | if (strcasecmp(found->key, key) == 0) { 126 | return found; 127 | } 128 | } 129 | return NULL; 130 | } 131 | int req_list_check_key(req_list_t *root, const char *key, const char *value) 132 | { 133 | req_list_t *found = req_list_get_key(root, key); 134 | if(found && strcasecmp(found->value, value) == 0) 135 | return 1; 136 | return 0; 137 | 138 | } 139 | req_list_t *req_list_set_from_string(req_list_t *root, const char *data) 140 | { 141 | int len = strlen(data); 142 | char* eq_ch = strchr(data, ':'); 143 | int key_len, value_len; 144 | req_list_t *ret = NULL; 145 | 146 | if (eq_ch == NULL) 147 | return NULL; 148 | key_len = eq_ch - data; 149 | value_len = len - key_len - 1; 150 | 151 | char *key = calloc(1, key_len + 1); 152 | char *value = calloc(1, value_len + 1); 153 | memcpy(key, data, key_len); 154 | memcpy(value, eq_ch + 1, value_len); 155 | 156 | ret = req_list_set_key(root, trimwhitespace(key), trimwhitespace(value)); 157 | free(key); 158 | free(value); 159 | return ret; 160 | } 161 | req_list_t *req_list_clear_key(req_list_t *root, const char *key) 162 | { 163 | return NULL; 164 | } 165 | -------------------------------------------------------------------------------- /components/oap-http/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-http/test/test_esp_request.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_esp_request.c 3 | * 4 | * Created on: Oct 6, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | 24 | #include "esp_request.h" 25 | #include "oap_test.h" 26 | #include "oap_debug.h" 27 | 28 | extern const uint8_t _root_ca_pem_start[] asm("_binary_comodo_ca_pem_start"); 29 | extern const uint8_t _root_ca_pem_end[] asm("_binary_comodo_ca_pem_end"); 30 | 31 | #define URL(PROT,PATH) #PROT"://openairproject.com/ota-test"#PATH 32 | 33 | static int make_http_get() { 34 | request_t* req = req_new(URL(http,/index.txt)); 35 | if (!req) return -1; 36 | req_setopt(req, REQ_REDIRECT_FOLLOW, "false"); 37 | req_setopt(req, REQ_SET_HEADER, HTTP_HEADER_CONNECTION_CLOSE); 38 | int resp = req_perform(req); 39 | req_clean(req); 40 | return resp == 301 ? 0 : resp; 41 | } 42 | 43 | static int make_https_get(int big) { 44 | request_t* req = req_new(big ? URL(https,/random32k.bin) : URL(https,/index.txt)); 45 | if (!req) return -1; 46 | req->ca_cert = req_parse_x509_crt((unsigned char*)_root_ca_pem_start, _root_ca_pem_end-_root_ca_pem_start); 47 | req_setopt(req, REQ_SET_HEADER, HTTP_HEADER_CONNECTION_CLOSE); 48 | int resp = req_perform(req); 49 | req_clean(req); 50 | return resp == 200 ? 0 : resp; 51 | } 52 | 53 | TEST_CASE("http request", "[esp-request]") { 54 | test_require_wifi(); 55 | TEST_ESP_OK(make_http_get()); 56 | } 57 | 58 | TEST_CASE("https request", "[esp-request]") { 59 | test_require_wifi(); 60 | TEST_ESP_OK(make_https_get(0)); 61 | } 62 | 63 | /* 64 | * there's a few problems with SSL stack on ESP32. 65 | * a single SSL request consumes a lot of stack and heap. 66 | * 67 | * so I've implemented a mutex to process them sequentially. 68 | * even with queuing them, they are still quite unreliable and timeout often. 69 | * 70 | * these tests are handy to look for memory leaks and stability in general. 71 | */ 72 | static QueueHandle_t https_client_task_queue; 73 | 74 | static void https_client_task() { 75 | int resp = make_https_get(1); 76 | xQueueSend(https_client_task_queue, &resp, 100); 77 | log_task_stack("sslclient"); 78 | vTaskDelete(NULL); 79 | } 80 | 81 | TEST_CASE("multiple ssl requests", "[esp-request]") { 82 | test_require_wifi(); 83 | int count = 4; 84 | if (!https_client_task_queue) https_client_task_queue = xQueueCreate(count, sizeof(int)); 85 | log_heap_size("before https requests"); 86 | for (int i = 0; i < count; i++) { 87 | char t[20]; //should be malloc ? 88 | sprintf(t, "https_task_%i", i); 89 | //6KB is MINIMUM for making ssl! 90 | xTaskCreate(https_client_task, t, 1024*6, NULL, 10, NULL); 91 | } 92 | int resp; 93 | for (int i = 0; i < count; i++) { 94 | xQueueReceive(https_client_task_queue, &resp, 20000/portTICK_PERIOD_MS); 95 | } 96 | log_heap_size("after http requests"); 97 | } 98 | 99 | 100 | static QueueHandle_t http_client_task_queue; 101 | 102 | static void http_client_task() { 103 | int resp = make_http_get(); 104 | xQueueSend(http_client_task_queue, &resp, 100); 105 | log_task_stack("httpclient"); 106 | vTaskDelete(NULL); 107 | } 108 | 109 | //no problems here, even if sometimes one or two fails 110 | TEST_CASE("multiple http requests", "[esp-request]") { 111 | test_require_wifi(); 112 | int count = 10; 113 | if (!http_client_task_queue) http_client_task_queue = xQueueCreate(count, sizeof(int)); 114 | log_heap_size("before http requests"); 115 | for (int i = 0; i < count; i++) { 116 | char t[20]; 117 | sprintf(t, "http_task_%i", i); 118 | xTaskCreate(http_client_task, t, 1024*5, NULL, 10, NULL); 119 | } 120 | int resp; 121 | for (int i = 0; i < count; i++) { 122 | xQueueReceive(http_client_task_queue, &resp, 20000/portTICK_PERIOD_MS); 123 | } 124 | log_heap_size("after http requests"); 125 | } 126 | 127 | 128 | -------------------------------------------------------------------------------- /components/oap-hw-bmx280/Kconfig: -------------------------------------------------------------------------------- 1 | menu "OAP BMx280 Sensor" 2 | 3 | config OAP_BMX280_ENABLED 4 | int "enable bmx280 sensor" 5 | default 1 6 | help 7 | todo 8 | 9 | config OAP_BMX280_ADDRESS 10 | hex "i2c address" 11 | default 0x76 12 | help 13 | Default address for bmx280 sensor is 0x76, it can be set to 0x77 by pulling up SDO pin. 14 | Adafruit bme280 board is configured for 0x77 as default. 15 | 16 | config OAP_BMX280_I2C_NUM 17 | int "i2c interface number" 18 | default 0 19 | help 20 | todo 21 | 22 | config OAP_BMX280_I2C_SDA_PIN 23 | int "gpio SDA pin" 24 | default 25 25 | help 26 | be careful with choosing gpio. i2c pins must be R/W. 27 | 28 | 29 | config OAP_BMX280_I2C_SCL_PIN 30 | int "SCL pin" 31 | default 26 32 | help 33 | see help for SDA pin 34 | 35 | config OAP_BMX280_ENABLED_AUX 36 | int "enable internal bmx280 sensor" 37 | default 0 38 | help 39 | todo 40 | 41 | config OAP_BMX280_ADDRESS_AUX 42 | hex "i2c address of internal sensor" 43 | default 0x77 44 | help 45 | If both external and internal sensor use the same i2c bus, they must be configured to use 46 | different addresses. 47 | Default address for bmx280 sensor is 0x76, it can be set to 0x77 by pulling up SDO pin. 48 | Adafruit bme280 board is configured for 0x77 as default. 49 | 50 | config OAP_BMX280_I2C_NUM_AUX 51 | int "i2c interface number for internal sensor" 52 | default 0 53 | help 54 | if both sensors use the same bus (default), sda/scl pins are ignored. 55 | 56 | config OAP_BMX280_I2C_SDA_PIN_AUX 57 | int "gpio SDA pin" 58 | default 25 59 | help 60 | be careful with choosing gpio. i2c pins must be R/W. 61 | 62 | 63 | config OAP_BMX280_I2C_SCL_PIN_AUX 64 | int "SCL pin" 65 | default 26 66 | help 67 | see help for SDA pin 68 | 69 | endmenu -------------------------------------------------------------------------------- /components/oap-hw-bmx280/bmx280.c: -------------------------------------------------------------------------------- 1 | /* 2 | * bmp280.c 3 | * 4 | * Created on: Feb 8, 2017 5 | * Author: kris 6 | * 7 | * based on https://github.com/LanderU/BMP280/blob/master/BMP280.c 8 | * 9 | * This file is part of OpenAirProject-ESP32. 10 | * 11 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 12 | * it under the terms of the GNU General Public License as published by 13 | * the Free Software Foundation, either version 3 of the License, or 14 | * (at your option) any later version. 15 | * 16 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with OpenAirProject-ESP32. If not, see . 23 | */ 24 | 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "sdkconfig.h" 30 | #include "oap_common.h" 31 | #include "oap_debug.h" 32 | #include "bmx280.h" 33 | #include "i2c_bme280.h" 34 | 35 | static char* TAG = "bmx280"; 36 | 37 | esp_err_t bmx280_measurement_loop(bmx280_config_t* bmx280_config) { 38 | i2c_comm_t i2c_comm = { 39 | .i2c_num = bmx280_config->i2c_num, 40 | .device_addr = bmx280_config->device_addr 41 | }; 42 | 43 | bme280_sensor_t bmx280_sensor = { 44 | .operation_mode = BME280_MODE_NORMAL, 45 | .i2c_comm = i2c_comm 46 | }; 47 | 48 | env_data_t result = { 49 | .sensor_idx = bmx280_config->sensor_idx 50 | }; 51 | 52 | // TODO strangely, if this is executed inside main task, LEDC fails to initialise properly PWM (and blinks in funny ways)... easy to reproduce. 53 | esp_err_t ret; 54 | if ((ret = BME280_init(&bmx280_sensor)) == ESP_OK) { 55 | while(1) { 56 | log_task_stack(TAG); 57 | if ((ret = BME280_read(&bmx280_sensor, &result)) == ESP_OK) { 58 | ESP_LOGD(TAG,"sensor (%d) => Temperature : %.2f C, Pressure: %.2f hPa, Humidity %.2f", result.sensor_idx, result.temp, result.pressure, result.humidity); 59 | if (bmx280_config->callback) { 60 | bmx280_config->callback(&result); 61 | } 62 | } else { 63 | ESP_LOGW(TAG, "Failed to read data"); 64 | } 65 | if (bmx280_config->interval > 0) { 66 | delay(bmx280_config->interval); 67 | } else { 68 | break; 69 | } 70 | } 71 | } else { 72 | ESP_LOGE(TAG, "Failed to initialise"); 73 | } 74 | return ret; 75 | } 76 | 77 | static void bmx280_task(bmx280_config_t* bmx280_config) { 78 | bmx280_measurement_loop(bmx280_config); 79 | vTaskDelete(NULL); 80 | } 81 | 82 | static uint8_t i2c_drivers[3] = {0}; 83 | 84 | esp_err_t bmx280_i2c_setup(bmx280_config_t* config) { 85 | if (config->i2c_num > 2) { 86 | ESP_LOGE(TAG, "invalid I2C BUS NUMBER (%d)", config->i2c_num); 87 | return ESP_FAIL; 88 | } 89 | if (i2c_drivers[config->i2c_num]) return ESP_OK; //already installed 90 | 91 | i2c_config_t i2c_conf; 92 | i2c_conf.mode = I2C_MODE_MASTER; 93 | i2c_conf.sda_io_num = config->sda_pin;//CONFIG_OAP_BMX280_I2C_SDA_PIN; 94 | i2c_conf.scl_io_num = config->scl_pin;//CONFIG_OAP_BMX280_I2C_SCL_PIN; 95 | i2c_conf.sda_pullup_en = GPIO_PULLUP_ENABLE; 96 | i2c_conf.scl_pullup_en = GPIO_PULLUP_ENABLE; 97 | i2c_conf.master.clk_speed = 100000; 98 | 99 | esp_err_t res; 100 | if ((res = i2c_param_config(config->i2c_num, &i2c_conf)) != ESP_OK) return res; 101 | 102 | ESP_LOGD(TAG, "install I2C driver (bus %d)", config->i2c_num); 103 | res = i2c_driver_install(config->i2c_num, I2C_MODE_MASTER, 0, 0, 0); 104 | if (res == ESP_OK) { 105 | i2c_drivers[config->i2c_num] = 1; 106 | } 107 | 108 | return res; 109 | } 110 | 111 | esp_err_t bmx280_init(bmx280_config_t* bmx280_config) { 112 | esp_err_t res; 113 | if ((res = bmx280_i2c_setup(bmx280_config)) == ESP_OK) { 114 | //2kb => ~380bytes free 115 | xTaskCreate((TaskFunction_t)bmx280_task, "bmx280_task", 1024*3, bmx280_config, DEFAULT_TASK_PRIORITY, NULL); 116 | } 117 | return res; 118 | } 119 | 120 | esp_err_t bmx280_set_hardware_config(bmx280_config_t* bmx280_config, uint8_t sensor_idx) { 121 | switch (sensor_idx) { 122 | case 0: 123 | if (!OAP_BMX280_ENABLED) return ESP_FAIL; 124 | bmx280_config->sensor_idx = 0; 125 | bmx280_config->i2c_num = OAP_BMX280_I2C_NUM; 126 | bmx280_config->device_addr = OAP_BMX280_ADDRESS; 127 | bmx280_config->sda_pin = OAP_BMX280_I2C_SDA_PIN; 128 | bmx280_config->scl_pin = OAP_BMX280_I2C_SCL_PIN; 129 | return ESP_OK; 130 | case 1: 131 | if (!OAP_BMX280_ENABLED_AUX) return ESP_FAIL; 132 | bmx280_config->sensor_idx = 1; 133 | bmx280_config->i2c_num = OAP_BMX280_I2C_NUM_AUX; 134 | bmx280_config->device_addr = OAP_BMX280_ADDRESS_AUX; 135 | bmx280_config->sda_pin = OAP_BMX280_I2C_SDA_PIN_AUX; 136 | bmx280_config->scl_pin = OAP_BMX280_I2C_SCL_PIN_AUX; 137 | return ESP_OK; 138 | default: 139 | return ESP_FAIL; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /components/oap-hw-bmx280/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /components/oap-hw-bmx280/i2c_bme280.h: -------------------------------------------------------------------------------- 1 | /* 2 | * This file is part of OpenAirProject-ESP32. 3 | * 4 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 5 | * it under the terms of the GNU General Public License as published by 6 | * the Free Software Foundation, either version 3 of the License, or 7 | * (at your option) any later version. 8 | * 9 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | * GNU General Public License for more details. 13 | * 14 | * You should have received a copy of the GNU General Public License 15 | * along with OpenAirProject-ESP32. If not, see . 16 | 17 | */ 18 | #ifndef __I2C_BME280_H 19 | #define __I2C_BME280_H 20 | 21 | #include 22 | #include 23 | #include "oap_data_env.h" 24 | 25 | #define BME280_MODE_NORMAL 0x03 //reads sensors at set interval 26 | #define BME280_MODE_FORCED 0x01 //reads sensors once when you write this register 27 | 28 | #define CHIP_TYPE_BMP 1 29 | #define CHIP_TYPE_BME 2 30 | 31 | #define HUMIDITY_MEAS_UNSUPPORTED -1 32 | 33 | typedef struct bmx280_calib_t { 34 | uint16_t dig_T1; 35 | int16_t dig_T2; 36 | int16_t dig_T3; 37 | uint16_t dig_P1; 38 | int16_t dig_P2; 39 | int16_t dig_P3; 40 | int16_t dig_P4; 41 | int16_t dig_P5; 42 | int16_t dig_P6; 43 | int16_t dig_P7; 44 | int16_t dig_P8; 45 | int16_t dig_P9; 46 | int8_t dig_H1; 47 | int16_t dig_H2; 48 | int8_t dig_H3; 49 | int16_t dig_H4; 50 | int16_t dig_H5; 51 | int8_t dig_H6; 52 | } bmx280_calib_t; 53 | 54 | typedef struct i2c_comm_t { 55 | uint8_t i2c_num; 56 | uint8_t device_addr; 57 | } i2c_comm_t; 58 | 59 | typedef struct bme280_sensor_t { 60 | uint8_t operation_mode; 61 | i2c_comm_t i2c_comm; 62 | bmx280_calib_t calib; 63 | uint8_t chip_type; 64 | } bme280_sensor_t; 65 | 66 | esp_err_t BME280_verify_chip(bme280_sensor_t* bme280_sensor); 67 | 68 | esp_err_t BME280_init(bme280_sensor_t* bme280_sensor); 69 | 70 | esp_err_t BME280_read(bme280_sensor_t* bme280_sensor, env_data_t* result); 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /components/oap-hw-bmx280/include/bmx280.h: -------------------------------------------------------------------------------- 1 | /* 2 | * bmp280.h 3 | * 4 | * Created on: Feb 8, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_BMP280_H_ 24 | #define MAIN_BMP280_H_ 25 | 26 | #include "oap_common.h" 27 | #include "oap_data_env.h" 28 | 29 | #define OAP_BMX280_ENABLED CONFIG_OAP_BMX280_ENABLED 30 | #define OAP_BMX280_I2C_NUM CONFIG_OAP_BMX280_I2C_NUM 31 | #define OAP_BMX280_ADDRESS CONFIG_OAP_BMX280_ADDRESS 32 | #define OAP_BMX280_I2C_SDA_PIN CONFIG_OAP_BMX280_I2C_SDA_PIN 33 | #define OAP_BMX280_I2C_SCL_PIN CONFIG_OAP_BMX280_I2C_SCL_PIN 34 | 35 | #define OAP_BMX280_ENABLED_AUX CONFIG_OAP_BMX280_ENABLED_AUX 36 | #define OAP_BMX280_I2C_NUM_AUX CONFIG_OAP_BMX280_I2C_NUM_AUX 37 | #define OAP_BMX280_ADDRESS_AUX CONFIG_OAP_BMX280_ADDRESS_AUX 38 | #define OAP_BMX280_I2C_SDA_PIN_AUX CONFIG_OAP_BMX280_I2C_SDA_PIN_AUX 39 | #define OAP_BMX280_I2C_SCL_PIN_AUX CONFIG_OAP_BMX280_I2C_SCL_PIN_AUX 40 | 41 | typedef void(*env_callback)(env_data_t*); 42 | 43 | typedef struct bmx280_config_t { 44 | 45 | uint8_t i2c_num; 46 | uint8_t device_addr; 47 | uint8_t sda_pin; 48 | uint8_t scl_pin; 49 | uint8_t sensor_idx; //sensor number (0 - 1) 50 | uint32_t interval; 51 | env_callback callback; 52 | 53 | } bmx280_config_t; 54 | 55 | esp_err_t bmx280_init(bmx280_config_t* config); 56 | 57 | esp_err_t bmx280_set_hardware_config(bmx280_config_t* bmx280_config, uint8_t sensor_idx); 58 | 59 | #endif /* MAIN_BMP280_H_ */ 60 | -------------------------------------------------------------------------------- /components/oap-hw-bmx280/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-hw-bmx280/test/test_bmx280.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_bmx280.c 3 | * 4 | * Created on: Sep 21, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "bmx280.h" 24 | #include "unity.h" 25 | 26 | esp_err_t bmx280_i2c_setup(bmx280_config_t* config); 27 | esp_err_t bmx280_measurement_loop(bmx280_config_t* bmx280_config); 28 | static env_data_t last_result; 29 | 30 | static void collect_result(env_data_t* result) { 31 | memcpy(&last_result, result, sizeof(env_data_t)); 32 | } 33 | 34 | static bmx280_config_t cfg = { 35 | .i2c_num = CONFIG_OAP_BMX280_I2C_NUM, 36 | .device_addr= CONFIG_OAP_BMX280_ADDRESS, 37 | .sda_pin= CONFIG_OAP_BMX280_I2C_SDA_PIN, 38 | .scl_pin= CONFIG_OAP_BMX280_I2C_SCL_PIN, 39 | .sensor_idx = 9, 40 | .interval = 0, //no repeat 41 | .callback = &collect_result 42 | }; 43 | 44 | TEST_CASE("bmx280 measurement","[bmx280]") { 45 | bzero(&last_result, 0); 46 | TEST_ASSERT_TRUE(CONFIG_OAP_BMX280_ENABLED); 47 | TEST_ESP_OK(bmx280_i2c_setup(&cfg)); 48 | TEST_ESP_OK(bmx280_measurement_loop(&cfg)); 49 | 50 | TEST_ASSERT_EQUAL_UINT(9, last_result.sensor_idx); 51 | TEST_ASSERT_TRUE_MESSAGE(last_result.temp > 10 && last_result.temp < 50, "invalid temperature"); //let's assume we do it indoors ;) 52 | TEST_ASSERT_TRUE_MESSAGE(last_result.pressure>850 && last_result.pressure < 1050, "invalid pressure"); 53 | if (last_result.humidity != -1) { 54 | TEST_ASSERT_TRUE_MESSAGE(last_result.humidity > 0 && last_result.humidity < 100, "invalid humidity"); //bme280 only 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /components/oap-hw-ext/Kconfig: -------------------------------------------------------------------------------- 1 | menu "OAP Peripherals" 2 | 3 | config OAP_LED_R_PIN 4 | int "led Red pin" 5 | default 12 6 | help 7 | ESP32 R/W gpio 8 | 9 | config OAP_LED_G_PIN 10 | int "led Green pin" 11 | default 27 12 | help 13 | ESP32 R/W gpio 14 | 15 | config OAP_LED_B_PIN 16 | int "led Blue pin" 17 | default 14 18 | help 19 | ESP32 R/W gpio 20 | 21 | config OAP_BTN_0_PIN 22 | int "button pin" 23 | default 35 24 | help 25 | ESP32 gpio 26 | 27 | endmenu -------------------------------------------------------------------------------- /components/oap-hw-ext/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /components/oap-hw-ext/ctrl_btn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * btn.c 3 | * 4 | * Created on: Feb 4, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "freertos/FreeRTOS.h" 29 | #include "freertos/task.h" 30 | #include "oap_common.h" 31 | #include "ctrl_btn.h" 32 | #include "esp_log.h" 33 | #include "esp_err.h" 34 | #include "driver/gpio.h" 35 | #include "freertos/queue.h" 36 | 37 | #define ESP_INTR_FLAG_DEFAULT 0 38 | #define TAG "btn" 39 | 40 | typedef struct { 41 | uint8_t gpio_num; 42 | uint32_t timestamp; 43 | } gpio_event_t; 44 | 45 | static QueueHandle_t gpio_evt_queue; 46 | static uint32_t last_click = 0; 47 | static btn_callback_f _callback = NULL; 48 | 49 | static void IRAM_ATTR gpio_isr_handler(void* arg) 50 | { 51 | uint32_t t = millis(); 52 | /* 53 | * TODO is there a way to programmatically eliminate flickering? 54 | */ 55 | if (t - last_click < 80) return; 56 | last_click = t; 57 | gpio_event_t gpio_evt = { 58 | .gpio_num = (uint8_t)(uint32_t)arg, 59 | .timestamp = t 60 | }; 61 | xQueueSendFromISR(gpio_evt_queue, &gpio_evt, NULL); 62 | } 63 | 64 | static void gpio_watchdog_task() { 65 | gpio_event_t gpio_evt; 66 | int count = 0; 67 | uint32_t first_click = 0; 68 | 69 | while(1) { 70 | if (xQueueReceive(gpio_evt_queue, &gpio_evt, 1000)) { 71 | _callback(SINGLE_CLICK); 72 | //20 sec to perform the action 73 | if (!first_click || gpio_evt.timestamp - first_click > 20000) { 74 | first_click = gpio_evt.timestamp; 75 | count = 0; 76 | } 77 | count++; 78 | ESP_LOGD(TAG, "click gpio[%d] [%d in sequence]",gpio_evt.gpio_num, count); 79 | 80 | //due to flickering we cannot precisely count all clicks anyway 81 | if (count == 10) { 82 | _callback(MANY_CLICKS); 83 | } 84 | if (count >= 20) { 85 | _callback(TOO_MANY_CLICKS); 86 | first_click=0; 87 | count=0; 88 | } 89 | } 90 | } 91 | } 92 | 93 | esp_err_t btn_configure(btn_callback_f callback) { 94 | _callback = callback; 95 | gpio_evt_queue = xQueueCreate(10, sizeof(gpio_event_t)); 96 | gpio_pad_select_gpio(CONFIG_OAP_BTN_0_PIN); 97 | gpio_set_direction(CONFIG_OAP_BTN_0_PIN, GPIO_MODE_INPUT); 98 | gpio_set_pull_mode(CONFIG_OAP_BTN_0_PIN, GPIO_PULLDOWN_ONLY); 99 | gpio_set_intr_type(CONFIG_OAP_BTN_0_PIN, GPIO_INTR_POSEDGE); 100 | gpio_install_isr_service(ESP_INTR_FLAG_DEFAULT); 101 | gpio_isr_handler_add(CONFIG_OAP_BTN_0_PIN, gpio_isr_handler, (void*) CONFIG_OAP_BTN_0_PIN); 102 | xTaskCreate((TaskFunction_t)gpio_watchdog_task, "gpio_watchdog_task", 1024*2, NULL, DEFAULT_TASK_PRIORITY+2, NULL); 103 | return ESP_OK; //TODO handle errors 104 | } 105 | 106 | bool is_ap_mode_pressed() { 107 | return gpio_get_level(CONFIG_OAP_BTN_0_PIN); 108 | } 109 | 110 | -------------------------------------------------------------------------------- /components/oap-hw-ext/include/ctrl_btn.h: -------------------------------------------------------------------------------- 1 | /* 2 | * btn.h 3 | * 4 | * Created on: Feb 4, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_BTN_H_ 24 | #define MAIN_BTN_H_ 25 | 26 | typedef enum { 27 | SINGLE_CLICK, 28 | MANY_CLICKS, 29 | TOO_MANY_CLICKS 30 | } btn_action_t; 31 | typedef void(*btn_callback_f)(btn_action_t); 32 | 33 | bool is_ap_mode_pressed(); 34 | esp_err_t btn_configure(btn_callback_f callback); 35 | 36 | #endif /* MAIN_BTN_H_ */ 37 | -------------------------------------------------------------------------------- /components/oap-hw-ext/include/rgb_led.h: -------------------------------------------------------------------------------- 1 | /* 2 | * led.h 3 | * 4 | * Created on: Feb 7, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_LED_H_ 24 | #define MAIN_LED_H_ 25 | 26 | #include "freertos/queue.h" 27 | 28 | typedef struct { float v[3]; } rgb_color_t; 29 | 30 | typedef enum { 31 | LED_SET = 0, 32 | LED_FADE_TO = 1, 33 | LED_BLINK = 2, 34 | LED_PULSE = 3 35 | } led_mode_t; 36 | 37 | typedef struct { 38 | led_mode_t mode; 39 | rgb_color_t color; 40 | uint32_t freq; 41 | } led_cmd_t; 42 | 43 | void led_init(int enabled, xQueueHandle cmd_queue); 44 | 45 | #endif /* MAIN_LED_H_ */ 46 | -------------------------------------------------------------------------------- /components/oap-hw-ext/rgb_led.c: -------------------------------------------------------------------------------- 1 | /* 2 | * led.c 3 | * 4 | * Created on: Feb 7, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | #include 23 | #include 24 | #include "freertos/FreeRTOS.h" 25 | #include "freertos/task.h" 26 | #include "freertos/xtensa_api.h" 27 | #include "freertos/queue.h" 28 | #include "driver/ledc.h" 29 | #include "driver/rtc_io.h" 30 | #include "driver/gpio.h" 31 | #include "esp_attr.h" 32 | #include "esp_err.h" 33 | #include "esp_log.h" 34 | #include 35 | #include "rgb_led.h" 36 | #include "oap_common.h" 37 | 38 | static const char* TAG = "rgbled"; 39 | static xQueueHandle cmd_queue; 40 | static gpio_num_t led_gpio[] = {CONFIG_OAP_LED_R_PIN,CONFIG_OAP_LED_G_PIN,CONFIG_OAP_LED_B_PIN}; 41 | 42 | #define DEFAULT_FREQ 1000 43 | 44 | static ledc_mode_t speed_mode = LEDC_HIGH_SPEED_MODE; 45 | 46 | static ledc_timer_config_t ledc_timer = { 47 | //set timer counter bit number 48 | .bit_num = LEDC_TIMER_10_BIT, 49 | //set frequency of pwm 50 | .freq_hz = 5000, 51 | //timer mode, 52 | .speed_mode = LEDC_HIGH_SPEED_MODE, 53 | //timer index 54 | .timer_num = LEDC_TIMER_0 55 | }; 56 | 57 | static int MAX_DUTY = 0; 58 | static rgb_color_t LED_OFF = {.v={0,0,0}}; 59 | 60 | //brightness for each of R/G/B. LED Green tends to be the brightest 61 | //so if we use the same resistors we need to compensate for it to get proper orange. 62 | //this probably should be configureble since it depends on particular LED and resistors. 63 | static float brightness[] = {1.0f,0.3f,1.0f}; 64 | 65 | static int calc_duty(rgb_color_t color, uint8_t c) { 66 | return lroundf(MAX_DUTY * fminf(color.v[c] * brightness[c], 1.0)); 67 | } 68 | 69 | void set_color(rgb_color_t color) { 70 | esp_err_t res; 71 | int duty; 72 | for (int c = 0; c < 3; c++) { 73 | duty = calc_duty(color,c); 74 | if ((res = ledc_set_duty(speed_mode, c, duty)) != ESP_OK) { 75 | ESP_LOGW(TAG, "ledc_set_duty(%d,%d,%d) error %d", speed_mode, c, duty, res); 76 | } 77 | if ((res = ledc_update_duty(speed_mode, c)) != ESP_OK) { 78 | ESP_LOGW(TAG, "ledc_update_duty(%d,%d) error %d", speed_mode, c, res); 79 | } 80 | } 81 | } 82 | 83 | void fade_to_color(rgb_color_t color, int time) { 84 | esp_err_t res; 85 | int duty; 86 | for (int c = 0; c < 3; c++) { 87 | duty = calc_duty(color,c); 88 | if ((res = ledc_set_fade_with_time(speed_mode, c, duty,time)) != ESP_OK) { 89 | ESP_LOGW(TAG, "ledc_set_fade_with_time(%d,%d,%d,%d) error %d", speed_mode, c, duty, time, res); 90 | } 91 | if ((res = ledc_fade_start(speed_mode, c, LEDC_FADE_NO_WAIT)) != ESP_OK) { 92 | ESP_LOGW(TAG, "ledc_fade_start(%d,%d) error %d", c, LEDC_FADE_NO_WAIT, res); 93 | } 94 | } 95 | } 96 | 97 | static void setup_ledc() { 98 | MAX_DUTY = pow(2,ledc_timer.bit_num)-1; 99 | ledc_timer_config(&ledc_timer); 100 | 101 | ledc_channel_config_t ledc_channel = { 102 | .channel = -1, 103 | .duty = -1, 104 | .gpio_num = -1, 105 | //GPIO INTR TYPE, as an example, we enable fade_end interrupt here. 106 | .intr_type = LEDC_INTR_FADE_END, 107 | //set LEDC mode, from ledc_mode_t 108 | .speed_mode = speed_mode, 109 | //set LEDC timer source, if different channel use one timer, 110 | //the frequency and bit_num of these channels should be the same 111 | .timer_sel = LEDC_TIMER_0 112 | }; 113 | 114 | for (int c = 0; c < 3; c++) { 115 | ledc_channel.channel = c; //LEDC_CHANNEL_0 to LEDC_CHANNEL_2 116 | ledc_channel.gpio_num = led_gpio[c]; 117 | ledc_channel.duty = 0; 118 | gpio_intr_disable(led_gpio[c]); 119 | ledc_channel_config(&ledc_channel); 120 | } 121 | //initialize fade service. 122 | ledc_fade_func_install(0); 123 | } 124 | 125 | static void led_cycle() { 126 | rgb_color_t color = {.v={1,1,1}}; 127 | led_cmd_t cmd = { 128 | .mode = LED_SET, 129 | .color = color 130 | }; 131 | int level = 0; 132 | int freq; 133 | while (1) { 134 | level = !level; 135 | freq = cmd.freq > 0 ? cmd.freq : DEFAULT_FREQ; 136 | switch (cmd.mode) { 137 | case LED_BLINK : 138 | //ESP_LOGD(TAG, "->blink (%d)", level); 139 | set_color(level ? cmd.color : LED_OFF); 140 | break; 141 | case LED_PULSE : 142 | //ESP_LOGD(TAG, "->pulse (%d)", level); 143 | fade_to_color(level ? cmd.color : LED_OFF, freq); 144 | break; 145 | case LED_FADE_TO: 146 | //ESP_LOGD(TAG, "->fade_to"); 147 | //this is causing some errors - cannot schedule fading when other is still ongoing? 148 | fade_to_color(cmd.color, freq); 149 | break; 150 | default: 151 | //ESP_LOGD(TAG, "->set"); 152 | freq = DEFAULT_FREQ; 153 | set_color(cmd.color); 154 | break; 155 | } 156 | //wait for another command 157 | if (xQueueReceive(cmd_queue, &cmd, freq / portTICK_PERIOD_MS)) { 158 | ESP_LOGD(TAG, "->received command"); 159 | //memcpy(&cmd, &received, sizeof(cmd)); 160 | } 161 | } 162 | } 163 | 164 | void led_init(int enabled, xQueueHandle _cmd_queue) 165 | { 166 | if (enabled) { 167 | cmd_queue = _cmd_queue; 168 | setup_ledc(); //this often conflicts with other i/o operations? e.g. bme280 init. 169 | xTaskCreate(led_cycle, "led_cycle", 1024*2, NULL, DEFAULT_TASK_PRIORITY+1, NULL); 170 | } else { 171 | for (int c = 0; c < 3; c++) { 172 | if (led_gpio[c] > 0) gpio_set_pull_mode(led_gpio[c], GPIO_PULLDOWN_ONLY); 173 | } 174 | } 175 | } 176 | 177 | -------------------------------------------------------------------------------- /components/oap-hw-pmsx003/Kconfig: -------------------------------------------------------------------------------- 1 | menu "OAP PMSx003 Sensor" 2 | 3 | config OAP_PM_UART_NUM 4 | hex "uart num" 5 | default 1 6 | help 7 | todo 8 | 9 | config OAP_PM_SENSOR_CONTROL_PIN 10 | int "sensor set gpio" 11 | default 10 12 | help 13 | R/W GPIO pin connected to sensor SET line - it enables/disables sensor. 14 | 15 | config OAP_PM_UART_RXD_PIN 16 | int "RX gpio" 17 | default 13 18 | help 19 | GPIO pin connected to sensor RX line. This pin can be R/O (>=34). 20 | 21 | config OAP_PM_UART_TXD_PIN 22 | int "TX gpio" 23 | default 5 24 | help 25 | Any gpio pin (no need to connect this line) 26 | 27 | config OAP_PM_UART_RTS_PIN 28 | int "RTS gpio" 29 | default 18 30 | help 31 | Any gpio pin (no need to connect this line) 32 | 33 | config OAP_PM_UART_CTS_PIN 34 | int "CTS gpio" 35 | default 19 36 | help 37 | Any gpio pin (no need to connect this line) 38 | 39 | config OAP_PM_ENABLED_AUX 40 | int "enable secondary PM sensor" 41 | default 0 42 | help 43 | todo 44 | 45 | config OAP_PM_UART_NUM_AUX 46 | hex "AUX uart num" 47 | default 2 48 | help 49 | todo 50 | 51 | config OAP_PM_SENSOR_CONTROL_PIN_AUX 52 | int "AUX sensor set gpio" 53 | default 2 54 | help 55 | R/W GPIO pin connected to sensor SET line - it enables/disables sensor. 56 | 57 | config OAP_PM_UART_RXD_PIN_AUX 58 | int "AUX RX gpio" 59 | default 15 60 | help 61 | GPIO pin connected to sensor RX line. This pin can be R/O (>=34). 62 | 63 | config OAP_PM_UART_TXD_PIN_AUX 64 | int "AUX TX gpio" 65 | default 5 66 | help 67 | Any gpio pin (no need to connect this line) 68 | 69 | config OAP_PM_UART_RTS_PIN_AUX 70 | int "AUX RTS gpio" 71 | default 18 72 | help 73 | Any gpio pin (no need to connect this line) 74 | 75 | config OAP_PM_UART_CTS_PIN_AUX 76 | int "AUX CTS gpio" 77 | default 19 78 | help 79 | Any gpio pin (no need to connect this line) 80 | 81 | endmenu -------------------------------------------------------------------------------- /components/oap-hw-pmsx003/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | -------------------------------------------------------------------------------- /components/oap-hw-pmsx003/include/pmsx003.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pms.h 3 | * 4 | * Created on: Feb 3, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_PMS_H_ 24 | #define MAIN_PMS_H_ 25 | 26 | #include "oap_common.h" 27 | #include "oap_data_pm.h" 28 | #include "driver/uart.h" 29 | 30 | typedef struct { 31 | uint8_t indoor; 32 | uint8_t enabled; //internal, read-only 33 | uint8_t sensor_idx; 34 | pm_data_callback_f callback; 35 | uint8_t set_pin; 36 | uart_port_t uart_num; 37 | uint8_t uart_txd_pin; 38 | uint8_t uart_rxd_pin; 39 | uint8_t uart_rts_pin; 40 | uint8_t uart_cts_pin; 41 | } pmsx003_config_t; 42 | 43 | /** 44 | * pm samples data is send to the queue. 45 | */ 46 | esp_err_t pmsx003_init(pmsx003_config_t* config); 47 | 48 | /** 49 | * enable/disable sensor. 50 | */ 51 | esp_err_t pmsx003_enable(pmsx003_config_t* config, uint8_t enabled); 52 | 53 | 54 | /** 55 | * fill config based on hardware configuration 56 | */ 57 | esp_err_t pmsx003_set_hardware_config(pmsx003_config_t* config, uint8_t sensor_idx); 58 | 59 | #endif /* MAIN_PMS_H_ */ 60 | -------------------------------------------------------------------------------- /components/oap-hw-pmsx003/pmsx003.c: -------------------------------------------------------------------------------- 1 | /* 2 | * pms.c 3 | * 4 | * Created on: Feb 3, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include "freertos/FreeRTOS.h" 28 | #include "driver/gpio.h" 29 | #include "driver/uart.h" 30 | #include "soc/uart_struct.h" 31 | #include "esp_log.h" 32 | #include "pmsx003.h" 33 | #include "oap_debug.h" 34 | 35 | /* 36 | * Driver for Plantower PMS3003 / PMS5003 / PMS7003 dust sensors. 37 | * PMSx003 sensors return two values for different environment of measurement. 38 | */ 39 | #define OAP_PM_UART_BUF_SIZE (128) 40 | 41 | static const char* TAG = "pmsX003"; 42 | 43 | esp_err_t pms_init_uart(pmsx003_config_t* config) { 44 | //configure UART 45 | uart_config_t uart_config = { 46 | .baud_rate = 9600, 47 | .data_bits = UART_DATA_8_BITS, 48 | .parity = UART_PARITY_DISABLE, 49 | .stop_bits = UART_STOP_BITS_1, 50 | .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, 51 | .rx_flow_ctrl_thresh = 122, 52 | }; 53 | esp_err_t ret; 54 | if ((ret = uart_param_config(config->uart_num, &uart_config)) != ESP_OK) { 55 | return ret; 56 | } 57 | 58 | if ((ret = uart_set_pin(config->uart_num, config->uart_txd_pin, config->uart_rxd_pin, config->uart_rts_pin, config->uart_cts_pin)) != ESP_OK) { 59 | return ret; 60 | } 61 | //Install UART driver( We don't need an event queue here) 62 | 63 | ret = uart_driver_install(config->uart_num, OAP_PM_UART_BUF_SIZE * 2, 0, 0, NULL,0); 64 | return ret; 65 | } 66 | 67 | static void configure_gpio(uint8_t gpio) { 68 | if (gpio > 0) { 69 | ESP_LOGD(TAG, "configure pin %d as output", gpio); 70 | gpio_pad_select_gpio(gpio); 71 | ESP_ERROR_CHECK(gpio_set_direction(gpio, GPIO_MODE_OUTPUT)); 72 | ESP_ERROR_CHECK(gpio_set_pull_mode(gpio, GPIO_PULLDOWN_ONLY)); 73 | } 74 | } 75 | 76 | static void set_gpio(uint8_t gpio, uint8_t enabled) { 77 | if (gpio > 0) { 78 | ESP_LOGD(TAG, "set pin %d => %d", gpio, enabled); 79 | gpio_set_level(gpio, enabled); 80 | } 81 | } 82 | 83 | void pms_init_gpio(pmsx003_config_t* config) { 84 | configure_gpio(config->set_pin); 85 | } 86 | 87 | static pm_data_t decodepm_data(uint8_t* data, uint8_t startByte) { 88 | pm_data_t pm = { 89 | .pm1_0 = ((data[startByte]<<8) + data[startByte+1]), 90 | .pm2_5 = ((data[startByte+2]<<8) + data[startByte+3]), 91 | .pm10 = ((data[startByte+4]<<8) + data[startByte+5]) 92 | }; 93 | return pm; 94 | } 95 | 96 | esp_err_t pms_uart_read(pmsx003_config_t* config, uint8_t data[32]) { 97 | int len = uart_read_bytes(config->uart_num, data, 32, 100 / portTICK_RATE_MS); 98 | if (config->enabled) { 99 | if (len >= 24 && data[0]==0x42 && data[1]==0x4d) { 100 | log_task_stack(TAG); 101 | //ESP_LOGI(TAG, "got frame of %d bytes", len); 102 | pm_data_t pm = decodepm_data(data, config->indoor ? 4 : 10); //atmospheric from 10th byte, standard from 4th 103 | pm.sensor_idx = config->sensor_idx; 104 | if (config->callback) { 105 | config->callback(&pm); 106 | } 107 | } else if (len > 0) { 108 | ESP_LOGW(TAG, "invalid frame of %d", len); //we often get an error after this :( 109 | return ESP_FAIL; 110 | } 111 | } 112 | return ESP_OK; 113 | } 114 | 115 | static void pms_task(pmsx003_config_t* config) { 116 | uint8_t data[32]; 117 | while(1) { 118 | pms_uart_read(config, data); 119 | } 120 | vTaskDelete(NULL); 121 | } 122 | 123 | esp_err_t pmsx003_enable(pmsx003_config_t* config, uint8_t enabled) { 124 | ESP_LOGI(TAG,"enable(%d)",enabled); 125 | config->enabled = enabled; 126 | set_gpio(config->set_pin, enabled); 127 | //if (config->heater_enabled) set_gpio(config->heater_pin, enabled); 128 | //if (config->fan_enabled) set_gpio(config->fan_pin, enabled); 129 | return ESP_OK; //todo 130 | } 131 | 132 | esp_err_t pmsx003_init(pmsx003_config_t* config) { 133 | pms_init_gpio(config); 134 | pmsx003_enable(config, 0); 135 | pms_init_uart(config); 136 | 137 | char task_name[100]; 138 | sprintf(task_name, "pms_sensor_%d", config->sensor_idx); 139 | 140 | //2kb leaves ~ 240 bytes free (depend on logs, printfs etc) 141 | xTaskCreate((TaskFunction_t)pms_task, task_name, 1024*3, config, DEFAULT_TASK_PRIORITY, NULL); 142 | return ESP_OK; //todo 143 | } 144 | 145 | esp_err_t pmsx003_set_hardware_config(pmsx003_config_t* config, uint8_t sensor_idx) { 146 | if (sensor_idx == 0) { 147 | config->sensor_idx = 0; 148 | config->set_pin = CONFIG_OAP_PM_SENSOR_CONTROL_PIN; 149 | config->uart_num = CONFIG_OAP_PM_UART_NUM; 150 | config->uart_txd_pin = CONFIG_OAP_PM_UART_TXD_PIN; 151 | config->uart_rxd_pin = CONFIG_OAP_PM_UART_RXD_PIN; 152 | config->uart_rts_pin = CONFIG_OAP_PM_UART_RTS_PIN; 153 | config->uart_cts_pin = CONFIG_OAP_PM_UART_CTS_PIN; 154 | return ESP_OK; 155 | } else if (sensor_idx == 1 && CONFIG_OAP_PM_ENABLED_AUX) { 156 | config->sensor_idx = 1; 157 | config->set_pin = CONFIG_OAP_PM_SENSOR_CONTROL_PIN_AUX; 158 | config->uart_num = CONFIG_OAP_PM_UART_NUM_AUX; 159 | config->uart_txd_pin = CONFIG_OAP_PM_UART_TXD_PIN_AUX; 160 | config->uart_rxd_pin = CONFIG_OAP_PM_UART_RXD_PIN_AUX; 161 | config->uart_rts_pin = CONFIG_OAP_PM_UART_RTS_PIN_AUX; 162 | config->uart_cts_pin = CONFIG_OAP_PM_UART_CTS_PIN_AUX; 163 | return ESP_OK; 164 | } else { 165 | return ESP_FAIL; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /components/oap-hw-pmsx003/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-hw-pmsx003/test/test_pmsx003.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_pmsx003.c 3 | * 4 | * Created on: Sep 21, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | 24 | #include "pmsx003.h" 25 | #include "oap_test.h" 26 | 27 | static pm_data_t last_result; 28 | 29 | static int got_result = 0; 30 | static void pms_test_callback(pm_data_t* result) { 31 | got_result = 1; 32 | memcpy(&last_result, result, sizeof(pm_data_t)); 33 | } 34 | 35 | static pmsx003_config_t config = { 36 | .indoor = 1, 37 | .enabled = 1, 38 | .sensor_idx = 7, 39 | .callback = pms_test_callback, 40 | .set_pin = CONFIG_OAP_PM_SENSOR_CONTROL_PIN, 41 | .uart_num = CONFIG_OAP_PM_UART_NUM, 42 | .uart_txd_pin = CONFIG_OAP_PM_UART_TXD_PIN, 43 | .uart_rxd_pin = CONFIG_OAP_PM_UART_RXD_PIN, 44 | .uart_rts_pin = CONFIG_OAP_PM_UART_RTS_PIN, 45 | .uart_cts_pin = CONFIG_OAP_PM_UART_CTS_PIN 46 | }; 47 | 48 | esp_err_t pms_init_uart(pmsx003_config_t* config); 49 | void pms_init_gpio(pmsx003_config_t* config); 50 | esp_err_t pms_uart_read(pmsx003_config_t* config, uint8_t data[32]); 51 | 52 | static int uart_installed = 0; 53 | 54 | void tearDown(void) 55 | { 56 | test_reset_hw(); 57 | } 58 | 59 | TEST_CASE("pmsx003 measurement","pmsx003") { 60 | pms_init_gpio(&config); 61 | if (!uart_installed) { 62 | TEST_ESP_OK(pms_init_uart(&config)); 63 | uart_installed = 1; 64 | } 65 | got_result = 0; 66 | uint8_t data[32]; 67 | 68 | test_timer_t t = { 69 | .started = 0, 70 | .wait_for = 10000 //it takes a while to spin it up 71 | }; 72 | 73 | TEST_ESP_OK(pmsx003_enable(&config, 1)); 74 | while (!got_result && !test_timeout(&t)) { 75 | pms_uart_read(&config, data); 76 | } 77 | TEST_ESP_OK(pmsx003_enable(&config, 0)); 78 | TEST_ASSERT_TRUE_MESSAGE(got_result, "timeout while waiting for measurement"); 79 | 80 | TEST_ASSERT_EQUAL_INT(config.sensor_idx, last_result.sensor_idx); 81 | TEST_ASSERT_TRUE_MESSAGE(last_result.pm1_0 > 0, "no pm1.0"); 82 | TEST_ASSERT_TRUE_MESSAGE(last_result.pm2_5 > 0, "no pm2.5"); 83 | TEST_ASSERT_TRUE_MESSAGE(last_result.pm10 > 0, "no pm10"); 84 | } 85 | 86 | 87 | -------------------------------------------------------------------------------- /components/oap-meter/Kconfig: -------------------------------------------------------------------------------- 1 | menu "OAP measurements" 2 | 3 | config OAP_PM_SAMPLE_BUF_SIZE 4 | int "PM sensor sample buffer size" 5 | default 120 6 | help 7 | Max number of samples that are stored during measurement period. PMSx003 sensor sends ~1 sample / sec. 8 | If more samples are collected during measurement, older samples get overriden. 9 | 10 | config OAP_HEATER_CONTROL_PIN 11 | int "external heater gpio" 12 | default 21 13 | help 14 | optional GPIO pin to control a heater. It mirrors state of SET gpio. (0 = none) 15 | 16 | config OAP_FAN_CONTROL_PIN 17 | int "external fan gpio" 18 | default 22 19 | help 20 | optional GPIO pin to control an additional fan. It mirrors state of SET gpio. (0 = none) 21 | 22 | endmenu -------------------------------------------------------------------------------- /components/oap-meter/component.mk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/components/oap-meter/component.mk -------------------------------------------------------------------------------- /components/oap-meter/include/meas_continuous.h: -------------------------------------------------------------------------------- 1 | /* 2 | * meas_continuous.h 3 | * 4 | * Created on: Mar 25, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_MEAS_CONTINUOUS_H_ 24 | #define MAIN_MEAS_CONTINUOUS_H_ 25 | 26 | typedef struct { 27 | 28 | } meas_continuous_params_t; 29 | 30 | #include "pm_meter.h" 31 | 32 | #endif /* MAIN_MEAS_CONTINUOUS_H_ */ 33 | -------------------------------------------------------------------------------- /components/oap-meter/include/meas_intervals.h: -------------------------------------------------------------------------------- 1 | /* 2 | * meas_intervals.h 3 | * 4 | * Created on: Mar 25, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_MEAS_INTERVALS_H_ 24 | #define MAIN_MEAS_INTERVALS_H_ 25 | 26 | 27 | #include "pm_meter.h" 28 | 29 | typedef struct { 30 | int warm_up_time; 31 | int meas_time; 32 | int meas_interval; 33 | } pm_meter_intervals_params_t; 34 | 35 | 36 | #endif /* MAIN_MEAS_INTERVALS_H_ */ 37 | -------------------------------------------------------------------------------- /components/oap-meter/include/pm_meter.h: -------------------------------------------------------------------------------- 1 | /* 2 | * meas.h 3 | * 4 | * Created on: Mar 25, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_MEAS_H_ 24 | #define MAIN_MEAS_H_ 25 | 26 | #include "oap_common.h" 27 | #include "oap_data.h" 28 | 29 | typedef struct { 30 | uint8_t heater_pin; 31 | uint8_t fan_pin; 32 | } pm_meter_aux_t; 33 | 34 | pm_meter_aux_t pm_meter_aux; 35 | 36 | typedef struct { 37 | uint8_t count; 38 | pm_data_t pm_data[2]; 39 | } pm_data_pair_t; 40 | 41 | typedef enum { 42 | PM_METER_START, 43 | PM_METER_RESULT, 44 | PM_METER_ERROR 45 | } pm_meter_event_t; 46 | 47 | typedef void(*pm_meter_output_f)(pm_meter_event_t event, void* pm_data); 48 | 49 | typedef void(*pm_sensor_enable_handler_f)(uint8_t enable); 50 | 51 | typedef struct { 52 | uint8_t count; 53 | pm_sensor_enable_handler_f handler[2]; 54 | } pm_sensor_enable_handler_pair_t; 55 | 56 | /** 57 | * @brief starts PM meter. it will now start collecting input samples until stop method is called 58 | * 59 | * params: 60 | * 1. handlers to enable/disable pm_sensors; 61 | * 2. pm_meter parameters 62 | * 3. output callback 63 | */ 64 | typedef void(*pm_meter_start_f)(pm_sensor_enable_handler_pair_t*, void*, pm_meter_output_f); 65 | 66 | /** 67 | * @brief stops PM meter. depending on a meter, this may generate 'RESULT' event. 68 | */ 69 | typedef void(*pm_meter_stop_f)(); 70 | 71 | typedef struct { 72 | pm_data_callback_f input; 73 | pm_meter_start_f start; 74 | pm_meter_stop_f stop; 75 | } pm_meter_t; 76 | 77 | 78 | 79 | #endif /* MAIN_MEAS_H_ */ 80 | -------------------------------------------------------------------------------- /components/oap-meter/meas_continuous.c: -------------------------------------------------------------------------------- 1 | /* 2 | * meas_continuous.c 3 | * 4 | * Created on: Mar 25, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "meas_continuous.h" 24 | 25 | //static char* TAG = "meas_cont"; 26 | // 27 | //typedef struct { 28 | // pmsx003_config_t config; 29 | // pm_data last; 30 | //} sensor_model_t; 31 | // 32 | //uint8_t sensor_count; 33 | //sensor_model_t* sensors; 34 | // 35 | //static void collect(pm_data* pm) { 36 | // 37 | //} 38 | // 39 | //static void start(pm_sensor_pair_config_t* pms_configs, meas_continuous_params_t* params, meas_strategy_callback callback) { 40 | // sensor_count = pms_configs->count; 41 | // sensors = malloc(sizeof(sensor_model_t)*sensor_count); 42 | // for (uint8_t c = 0; c < sensor_count; c++) { 43 | // sensor_model_t* sensor = sensors+c; 44 | // memset(sensor, 0, sizeof(sensor_model_t)); 45 | // memcpy(&sensor->config, pms_configs->sensor[c], sizeof(pmsx003_config_t)); 46 | // } 47 | //} 48 | // 49 | pm_meter_t pm_meter_continuous = { 50 | .input = NULL, 51 | .start = NULL, 52 | .stop = NULL 53 | }; 54 | -------------------------------------------------------------------------------- /components/oap-meter/meas_intervals.c: -------------------------------------------------------------------------------- 1 | /* 2 | * meas_intervals.c 3 | * 4 | * Created on: Mar 25, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "meas_intervals.h" 24 | #include "esp_log.h" 25 | #include "oap_common.h" 26 | #include "oap_debug.h" 27 | #include "esp_err.h" 28 | #include "freertos/task.h" 29 | 30 | static char* TAG = "meter_intv"; 31 | 32 | typedef struct { 33 | pm_sensor_enable_handler_f handler; 34 | uint16_t sample_count; 35 | pm_data_t* samples; 36 | } sensor_model_t; 37 | 38 | static sensor_model_t* sensors; 39 | static uint8_t sensor_count; 40 | static pm_meter_output_f _callback; 41 | static pm_meter_intervals_params_t _params; 42 | 43 | static long startedAt; 44 | 45 | static void pm_data_print(char* str, uint8_t sensor, pm_data_t* pm) { 46 | ESP_LOGI(TAG, "%s[%d] pm1.0=%d pm2.5=%d pm10=%d", str, sensor, pm->pm1_0, pm->pm2_5, pm->pm10); 47 | } 48 | 49 | static void collect(pm_data_t* pm) { 50 | sensor_model_t* sensor = sensors+pm->sensor_idx; 51 | 52 | pm_data_t* buf = sensor->samples+(sensor->sample_count % CONFIG_OAP_PM_SAMPLE_BUF_SIZE); 53 | memcpy(buf, pm, sizeof(pm_data_t)); 54 | 55 | if (millis() - startedAt > _params.warm_up_time * 1000) { 56 | sensor->sample_count++; 57 | pm_data_print("collect", pm->sensor_idx, buf); 58 | } else { 59 | pm_data_print("warming", pm->sensor_idx, buf); 60 | } 61 | } 62 | 63 | static void enable_sensors() { 64 | ESP_LOGI(TAG, "enable_sensors"); 65 | 66 | for (uint8_t s = 0; s < sensor_count; s++) { 67 | sensors[s].sample_count = 0; 68 | sensors[s].handler(1); 69 | } 70 | } 71 | 72 | static esp_err_t pm_meter_sample(uint8_t s, pm_data_t* result, uint8_t disable_sensor) { 73 | sensor_model_t* sensor = sensors+s; 74 | 75 | if (disable_sensor) { 76 | sensor->handler(0); 77 | } 78 | 79 | uint16_t count = sensor->sample_count > CONFIG_OAP_PM_SAMPLE_BUF_SIZE ? CONFIG_OAP_PM_SAMPLE_BUF_SIZE : sensor->sample_count; 80 | if (count == 0) { 81 | ESP_LOGW(TAG, "no samples recorded for sensor %d", s); 82 | return ESP_FAIL; 83 | } 84 | 85 | memset(result, 0, sizeof(pm_data_t)); 86 | pm_data_t* sample; 87 | for (uint16_t i = 0; i < count; i++) { 88 | sample = sensor->samples+i; 89 | result->pm1_0 += sample->pm1_0; 90 | result->pm2_5 += sample->pm2_5; 91 | result->pm10 += sample->pm10; 92 | } 93 | 94 | result->pm1_0 /= count; 95 | result->pm2_5 /= count; 96 | result->pm10 /= count; 97 | result->sensor_idx = s; 98 | 99 | ESP_LOGI(TAG, "stop measurement for sensor %d, recorded %d samples", s, count); 100 | pm_data_print("average", s, result); 101 | 102 | return ESP_OK; 103 | } 104 | 105 | static void task() { 106 | int delay_sec = (_params.meas_interval-_params.meas_time); 107 | while (1) { 108 | log_task_stack("pm_meter_trigger"); 109 | 110 | _callback(PM_METER_START,NULL); 111 | 112 | startedAt = millis(); 113 | 114 | enable_sensors(); 115 | 116 | delay(_params.meas_time * 1000); 117 | 118 | pm_data_pair_t pm_data_pair = { 119 | .count = sensor_count 120 | }; 121 | 122 | uint8_t ok = 1; 123 | for (uint8_t s = 0; ok && s < sensor_count; s++) { 124 | ESP_LOGI(TAG, "compute results for sensor %d", s); 125 | if (pm_meter_sample(s, pm_data_pair.pm_data+s, delay_sec>0) != ESP_OK) { 126 | _callback(PM_METER_ERROR, "cannot calculate result"); 127 | ok = 0; 128 | } 129 | } 130 | 131 | if (ok) { 132 | _callback(PM_METER_RESULT,&pm_data_pair); 133 | } 134 | 135 | if (delay_sec > 0) { 136 | delay(delay_sec * 1000); 137 | } else { 138 | delay(10); 139 | } 140 | } 141 | } 142 | 143 | static TaskHandle_t task_handle = NULL; 144 | static void start(pm_sensor_enable_handler_pair_t* pm_sensor_handlers, pm_meter_intervals_params_t* params, pm_meter_output_f callback) { 145 | ESP_LOGI(TAG, "start"); 146 | _callback = callback; 147 | memcpy(&_params, params, sizeof(pm_meter_intervals_params_t)); 148 | 149 | sensor_count = pm_sensor_handlers->count; 150 | sensors = malloc(sizeof(sensor_model_t)*sensor_count); 151 | for (uint8_t c = 0; c < sensor_count; c++) { 152 | sensor_model_t* sensor = sensors+c; 153 | memset(sensor, 0, sizeof(sensor_model_t)); 154 | sensor->handler = pm_sensor_handlers->handler[c]; 155 | sensor->samples = malloc(sizeof(pm_data_t)*CONFIG_OAP_PM_SAMPLE_BUF_SIZE); 156 | } 157 | xTaskCreate(task, "pm_meter_intervals", 1024*4, NULL, DEFAULT_TASK_PRIORITY, &task_handle); 158 | } 159 | 160 | static void stop() { 161 | if (task_handle) { 162 | vTaskDelete(task_handle); 163 | task_handle = NULL; 164 | } 165 | } 166 | 167 | pm_meter_t pm_meter_intervals = { 168 | .input = &collect, 169 | .start = (pm_meter_start_f)&start, 170 | .stop = &stop 171 | }; 172 | -------------------------------------------------------------------------------- /components/oap-meter/pm_meter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * meas.c 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "pm_meter.h" 24 | 25 | pm_meter_aux_t pm_meter_aux = { 26 | .heater_pin = CONFIG_OAP_HEATER_CONTROL_PIN, 27 | .fan_pin = CONFIG_OAP_FAN_CONTROL_PIN 28 | }; 29 | 30 | 31 | -------------------------------------------------------------------------------- /components/oap-meter/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-meter/test/test_pm_meter.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_meas.c 3 | * 4 | * Created on: Sep 24, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | 24 | #include "pm_meter.h" 25 | #include "meas_intervals.h" 26 | #include "oap_test.h" 27 | #include "freertos/task.h" 28 | 29 | extern pm_meter_t pm_meter_intervals; 30 | 31 | static int fake_sensor0_enabled = 0; 32 | static int fake_sensor1_enabled = 0; 33 | static list_t* strategy_events = NULL; 34 | 35 | #define TAG "test" 36 | 37 | typedef struct { 38 | pm_meter_event_t event_type; 39 | char* error; 40 | pm_data_pair_t* result; 41 | } test_meas_record_t; 42 | 43 | static void strategy_callback(pm_meter_event_t event, void* data) { 44 | test_meas_record_t* record = malloc(sizeof(test_meas_record_t)); 45 | memset(record, 0, sizeof(test_meas_record_t)); 46 | 47 | record->event_type = event; 48 | switch (event) { 49 | case PM_METER_START: 50 | ESP_LOGI(TAG, "MEAS_START"); 51 | break; 52 | case PM_METER_RESULT : 53 | ESP_LOGI(TAG, "MEAS_RESULT"); 54 | record->result = malloc(sizeof(pm_data_pair_t)); 55 | memcpy(record->result, data, sizeof(pm_data_pair_t)); 56 | break; 57 | case PM_METER_ERROR: 58 | ESP_LOGI(TAG, "MEAS_ERROR: %s", (char*)data); 59 | record->error = strdup((char*)data); 60 | break; 61 | } 62 | list_insert(strategy_events, record); 63 | } 64 | 65 | 66 | static void sensor_handler0(uint8_t enable) { 67 | fake_sensor0_enabled = enable; 68 | } 69 | static void sensor_handler1(uint8_t enable) { 70 | fake_sensor1_enabled = enable; 71 | } 72 | 73 | static pm_sensor_enable_handler_pair_t pm_sensor_handler_pair; 74 | static pm_meter_intervals_params_t strategy_test_params; 75 | 76 | static TaskHandle_t fake_sensor_task_handle = NULL; 77 | 78 | static void fake_sensor() { 79 | pm_data_t sample0 = { 80 | .pm1_0 = 0, 81 | .pm2_5 = 0, 82 | .pm10 = 0, 83 | .sensor_idx = 0 84 | }; 85 | 86 | pm_data_t sample1 = { 87 | .pm1_0 = 1, 88 | .pm2_5 = 2, 89 | .pm10 = 3, 90 | .sensor_idx = 1 91 | }; 92 | 93 | while (1) { 94 | if (fake_sensor0_enabled) { 95 | pm_meter_intervals.input(&sample0); 96 | sample0.pm1_0++; 97 | sample0.pm2_5+=2; 98 | sample0.pm10+=4; 99 | } 100 | if (fake_sensor1_enabled) { 101 | pm_meter_intervals.input(&sample1); 102 | } 103 | delay(100); 104 | } 105 | } 106 | 107 | static int has_result(void* data) { 108 | return data && ((test_meas_record_t*)data)->event_type == PM_METER_RESULT; 109 | } 110 | static int free_record(test_meas_record_t* record) { 111 | if (record->error) free(record->error); 112 | if (record->result) free(record->result); 113 | free(record); 114 | return 0; 115 | } 116 | 117 | TEST_CASE("meas intervals","[meas]") { 118 | 119 | //configure 120 | pm_sensor_handler_pair.count = 2; 121 | pm_sensor_handler_pair.handler[0] = &sensor_handler0; 122 | pm_sensor_handler_pair.handler[1] = &sensor_handler1; 123 | 124 | strategy_test_params.warm_up_time = 1; //one sec warming 125 | strategy_test_params.meas_time = 3, //two sec collect 126 | strategy_test_params.meas_interval = 10; 127 | 128 | strategy_events = list_createList(); 129 | xTaskCreate(fake_sensor, "fake_sensor", 2*1024, NULL, DEFAULT_TASK_PRIORITY, &fake_sensor_task_handle); 130 | 131 | pm_meter_intervals.start(&pm_sensor_handler_pair, &strategy_test_params, strategy_callback); 132 | list_t* result_record; 133 | 134 | //wait a bit longer for a result 135 | test_timer_t timer = {.started = 0, .wait_for = strategy_test_params.meas_time * 1000 + 1000}; 136 | while ((result_record = list_find(strategy_events, &has_result)) == NULL && !test_timeout(&timer)) { 137 | delay(50); 138 | } 139 | 140 | //cleanup 141 | pm_meter_intervals.stop(); 142 | vTaskDelete(fake_sensor_task_handle); 143 | 144 | //check 145 | if (!result_record) { 146 | list_deleteListAndValues(strategy_events, (node_value_predicate)&free_record); 147 | TEST_FAIL_MESSAGE("timeout while waiting for measurement result_record"); 148 | } else { 149 | pm_data_pair_t* meas_data = ((test_meas_record_t*)(result_record->value))->result; 150 | //sensor 0 151 | TEST_ASSERT_EQUAL_INT8(0, meas_data->pm_data[0].sensor_idx); 152 | TEST_ASSERT_MESSAGE(meas_data->pm_data[0].pm1_0 >= 19 && meas_data->pm_data[0].pm1_0 <= 21, "invalid 0->pm1.0 avg"); 153 | TEST_ASSERT_MESSAGE(meas_data->pm_data[0].pm2_5 >= 38 && meas_data->pm_data[0].pm2_5 <= 42, "invalid 0->pm2.5 avg"); 154 | TEST_ASSERT_MESSAGE(meas_data->pm_data[0].pm10 >= 76 && meas_data->pm_data[0].pm10 <= 84, "invalid 0->pm10 avg"); 155 | TEST_ASSERT_FALSE_MESSAGE(fake_sensor0_enabled, "sensor0 not disabled after measurement"); 156 | 157 | //sensor 1 158 | TEST_ASSERT_EQUAL_INT8(1, meas_data->pm_data[1].sensor_idx); 159 | TEST_ASSERT_EQUAL_INT16(1, meas_data->pm_data[1].pm1_0); 160 | TEST_ASSERT_EQUAL_INT16(2, meas_data->pm_data[1].pm2_5); 161 | TEST_ASSERT_EQUAL_INT16(3, meas_data->pm_data[1].pm10); 162 | TEST_ASSERT_FALSE_MESSAGE(fake_sensor1_enabled, "sensor1 not disabled after measurement"); 163 | list_deleteListAndValues(strategy_events, (node_value_predicate)&free_record); 164 | } 165 | 166 | } 167 | -------------------------------------------------------------------------------- /components/oap-ota/Kconfig: -------------------------------------------------------------------------------- 1 | menu "OAP OTA updates" 2 | 3 | config OAP_OTA_ENABLED 4 | int "enable OTA updates" 5 | default 1 6 | help 7 | enable automatic over-the-air updates 8 | 9 | config OAP_OTA_BIN_URI_PREFIX 10 | string "bin uri prefix" 11 | default "https://openairproject.com/ota/" 12 | help 13 | This prefix will be used to construct a full URI of a binary with OTA file. 14 | It is recommended to define as strictly as possible to increase security. 15 | Malicious index file won't be able to force update from different server / path. 16 | 17 | config OAP_OTA_INDEX_URI 18 | string "index uri" 19 | default "https://openairproject.com/ota/index.txt" 20 | help 21 | full URI to file with OTA definition 22 | 23 | endmenu -------------------------------------------------------------------------------- /components/oap-ota/comodo_ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU 3 | MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs 4 | IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290 5 | MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux 6 | FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h 7 | bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v 8 | dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt 9 | H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9 10 | uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX 11 | mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX 12 | a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN 13 | E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0 14 | WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD 15 | VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0 16 | Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU 17 | cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx 18 | IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN 19 | AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH 20 | YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5 21 | 6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC 22 | Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX 23 | c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a 24 | mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ= 25 | -----END CERTIFICATE----- -------------------------------------------------------------------------------- /components/oap-ota/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | # GitHub (https://www.digicert.com/CACerts/DigiCertHighAssuranceEVRootCA.crt) 11 | #COMPONENT_EMBED_TXTFILES = digicert_ca.pem 12 | 13 | # openairproject.com (CloudFront) 14 | COMPONENT_EMBED_TXTFILES = comodo_ca.pem 15 | -------------------------------------------------------------------------------- /components/oap-ota/digicert_ca.crt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/components/oap-ota/digicert_ca.crt -------------------------------------------------------------------------------- /components/oap-ota/digicert_ca.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs 3 | MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 4 | d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j 5 | ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL 6 | MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3 7 | LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug 8 | RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm 9 | +9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW 10 | PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM 11 | xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB 12 | Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3 13 | hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg 14 | EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF 15 | MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA 16 | FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec 17 | nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z 18 | eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF 19 | hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2 20 | Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe 21 | vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep 22 | +OkuE6N36B9K 23 | -----END CERTIFICATE----- 24 | -------------------------------------------------------------------------------- /components/oap-ota/include/ota.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ota.h 3 | * 4 | * Created on: Sep 10, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OTA_INCLUDE_OTA_H_ 24 | #define COMPONENTS_OTA_INCLUDE_OTA_H_ 25 | 26 | #include "oap_common.h" 27 | #include "cJSON.h" 28 | 29 | #define OAP_OTA_ENABLED CONFIG_OAP_OTA_ENABLED 30 | #define OAP_OTA_BIN_URI_PREFIX CONFIG_OAP_OTA_BIN_URI_PREFIX 31 | #define OAP_OTA_INDEX_URI CONFIG_OAP_OTA_INDEX_URI 32 | 33 | void start_ota_task(cJSON* user_ota_config); 34 | void reset_to_factory_partition(); 35 | 36 | #endif /* COMPONENTS_OTA_INCLUDE_OTA_H_ */ 37 | -------------------------------------------------------------------------------- /components/oap-ota/ota_int.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ota_int.h 3 | * 4 | * Created on: Sep 14, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_OTA_OTA_INT_H_ 24 | #define COMPONENTS_OTA_OTA_INT_H_ 25 | 26 | 27 | #include "ota.h" 28 | #include "esp_err.h" 29 | #include "esp_ota_ops.h" 30 | #include "oap_version.h" 31 | 32 | #define OAP_OTA_ERR_REQUEST_FAILED 0x1001 33 | #define OAP_OTA_ERR_NO_UPDATES 0x1002 34 | #define OAP_OTA_ERR_EMPTY_RESPONSE 0x1003 35 | #define OAP_OTA_ERR_MALFORMED_INFO 0x1004 36 | #define OAP_OTA_ERR_SHA_MISMATCH 0x1005 37 | 38 | typedef struct { 39 | char* bin_uri_prefix; 40 | char* index_uri; 41 | unsigned int interval; // for <=0 it checks only once 42 | int commit_and_reboot; 43 | const esp_partition_t *update_partition; 44 | unsigned long min_version; 45 | } ota_config_t; 46 | 47 | typedef struct { 48 | char* sha; 49 | char* file; 50 | oap_version_t ver; 51 | } ota_info_t; 52 | 53 | /* 54 | * ota_info has to be freed with free_ota_info 55 | */ 56 | esp_err_t is_ota_available(ota_config_t* ota_config, ota_info_t* ota_info); 57 | 58 | /* 59 | * ota_info has to be freed with free_ota_info 60 | */ 61 | esp_err_t fetch_last_ota_info(ota_config_t* ota_config, ota_info_t* ota_info); 62 | void free_ota_info(ota_info_t* ota_info); 63 | esp_err_t parse_ota_info(ota_info_t* ota_info, char* line, int len); 64 | esp_err_t check_ota(ota_config_t* ota_config); 65 | 66 | 67 | #endif /* COMPONENTS_OTA_OTA_INT_H_ */ 68 | -------------------------------------------------------------------------------- /components/oap-ota/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-ota/test/files/hello-world.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/components/oap-ota/test/files/hello-world.bin -------------------------------------------------------------------------------- /components/oap-ota/test/files/index-sha-mismatch.txt: -------------------------------------------------------------------------------- 1 | 1.2.3|hello-world.bin|99999999b5d1f4e98d810a36e361b84f62d8363de55fba487b81ebe0b3d4f676 2 | -------------------------------------------------------------------------------- /components/oap-ota/test/files/index.txt: -------------------------------------------------------------------------------- 1 | 1.2.3|hello-world.bin|304717e6b5d1f4e98d810a36e361b84f62d8363de55fba487b81ebe0b3d4f676 2 | -------------------------------------------------------------------------------- /components/oap-ota/test/test_ota.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "unity.h" 7 | #include "nvs.h" 8 | #include "nvs_flash.h" 9 | #include "esp_partition.h" 10 | #include "esp_log.h" 11 | #include 12 | #include "ota.h" 13 | #include "bootwifi.h" 14 | #include "oap_test.h" 15 | #include "oap_common.h" 16 | #include "oap_version.h" 17 | #include "mbedtls/sha256.h" 18 | 19 | #include "../ota_int.h" 20 | 21 | static const char* TAG = "test_ota"; 22 | 23 | static ota_config_t ota_test_config = { 24 | .index_uri = "https://openairproject.com/ota/test/index.txt", 25 | .bin_uri_prefix = "https://openairproject.com/ota/test/", 26 | .commit_and_reboot = 0, 27 | .update_partition = NULL, 28 | .interval = 0 29 | }; 30 | 31 | static ota_info_t hello_world_info = { 32 | .file = "hello-world.bin", 33 | .sha = "304717e6b5d1f4e98d810a36e361b84f62d8363de55fba487b81ebe0b3d4f676", 34 | .ver = { 35 | .major = 1, 36 | .minor = 2, 37 | .patch = 3 38 | } 39 | }; 40 | 41 | void sha_to_hexstr(unsigned char hash[32], unsigned char hex[64]); 42 | 43 | static void TEST_ASSERT_EQUAL_VER(uint8_t expected_major, uint8_t expected_minor, uint8_t expected_patch, oap_version_t* version) { 44 | TEST_ASSERT_EQUAL_INT(expected_major, version->major); 45 | TEST_ASSERT_EQUAL_INT(expected_minor, version->minor); 46 | TEST_ASSERT_EQUAL_INT(expected_patch, version->patch); 47 | } 48 | 49 | TEST_CASE("sha","[ota]") 50 | { 51 | char* input = "hello world"; 52 | char* output = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9"; 53 | 54 | unsigned char hash[32]; 55 | unsigned char hex[65]; 56 | hex[64] = 0; 57 | 58 | //single value 59 | mbedtls_sha256((unsigned char*)input, strlen(input), hash, 0); 60 | sha_to_hexstr(hash, hex); 61 | TEST_ASSERT_EQUAL_STRING(output, hex); 62 | 63 | //in parts 64 | mbedtls_sha256_context sha_context; 65 | mbedtls_sha256_init(&sha_context); 66 | mbedtls_sha256_starts(&sha_context,0); 67 | for (int i = 0; i < strlen(input); i++) { 68 | mbedtls_sha256_update(&sha_context, (unsigned char *)input+i, 1); 69 | } 70 | mbedtls_sha256_finish(&sha_context, hash); 71 | mbedtls_sha256_free(&sha_context); 72 | sha_to_hexstr(hash, hex); 73 | TEST_ASSERT_EQUAL_STRING(output, hex); 74 | } 75 | 76 | 77 | TEST_CASE("fetch_last_ota_info", "[ota]") 78 | { 79 | test_require_wifi(); 80 | ota_info_t info; 81 | /* 82 | * heap consumption goes to 0 after ~5 requests 83 | */ 84 | size_t curr_heap = 0; 85 | size_t prev_heap = 0; 86 | for (int i = 0; i < 1; i++) { 87 | curr_heap = xPortGetFreeHeapSize(); 88 | ESP_LOGW(TAG, "REQUEST %d (heap %u, %d bytes)", i, curr_heap, curr_heap-prev_heap); 89 | prev_heap = curr_heap; 90 | TEST_ESP_OK(fetch_last_ota_info(&ota_test_config, &info)); 91 | TEST_ASSERT_EQUAL_STRING(hello_world_info.file, info.file); 92 | TEST_ASSERT_EQUAL_VER(hello_world_info.ver.major,hello_world_info.ver.minor,hello_world_info.ver.patch,&info.ver); 93 | TEST_ASSERT_EQUAL_STRING(hello_world_info.sha, info.sha); 94 | if (i) delay(1000); 95 | } 96 | } 97 | 98 | //TEST_CASE("fetch_last_ota_info - LL", "[ota]") 99 | //{ 100 | // test_require_wifi(); 101 | // ota_info_t info = { 102 | // .sha = NULL, 103 | // .file = NULL 104 | // }; 105 | // /* 106 | // * heap consumption goes to 0 after ~5 requests 107 | // */ 108 | // size_t curr_heap = 0; 109 | // size_t prev_heap = 0; 110 | // for (int i = 0; i < 1000; i++) { 111 | // curr_heap = xPortGetFreeHeapSize(); 112 | // ESP_LOGW(TAG, "REQUEST %d (heap %u, %d bytes)", i, curr_heap, curr_heap-prev_heap); 113 | // prev_heap = curr_heap; 114 | // fetch_last_ota_info(&ota_test_config, &info); 115 | // free_ota_info(&info); 116 | // if (i) delay(1000); 117 | // } 118 | //} 119 | 120 | TEST_CASE("parse_ota_info","[ota]") 121 | { 122 | ota_info_t info; 123 | char* data = "1.2.3|hello-world.bin|929fd82b12f4e67cfa08a14e763232a95820b7f2b2edcce744e1c1711c7c9e04\r\n"; 124 | parse_ota_info(&info, data, strlen(data)); 125 | 126 | TEST_ASSERT_EQUAL_STRING("hello-world.bin", info.file); 127 | TEST_ASSERT_EQUAL_VER(1,2,3,&info.ver); 128 | TEST_ASSERT_EQUAL_STRING("929fd82b12f4e67cfa08a14e763232a95820b7f2b2edcce744e1c1711c7c9e04", info.sha); 129 | } 130 | 131 | //TEST_CASE("download_ota_binary", "[ota]") 132 | //{ 133 | // test_require_wifi(); 134 | // TEST_ESP_OK(download_ota_binary(&ota_test_config, &hello_world_info, NULL)); 135 | //} 136 | 137 | TEST_CASE("full ota", "[ota]") 138 | { 139 | test_require_wifi(); 140 | ota_config_t ota_config; 141 | memcpy(&ota_config, &ota_test_config, sizeof(ota_config_t)); 142 | ota_config.min_version=oap_version_num(hello_world_info.ver) - 1; //one patch earlier 143 | 144 | int ret = check_ota(&ota_config); 145 | 146 | //if OTA partition is too small, you'll get 'segment invalid length error' 147 | TEST_ESP_OK(ret); 148 | TEST_ASSERT_NOT_NULL(ota_config.update_partition); 149 | } 150 | 151 | TEST_CASE("skip ota if up-to-date", "[ota]") 152 | { 153 | test_require_wifi(); 154 | ota_config_t ota_config; 155 | memcpy(&ota_config, &ota_test_config, sizeof(ota_config_t)); 156 | ota_config.min_version=oap_version_num(hello_world_info.ver); //the same version 157 | 158 | int ret = check_ota(&ota_config); 159 | TEST_ASSERT_EQUAL_UINT16(OAP_OTA_ERR_NO_UPDATES, ret); 160 | } 161 | 162 | TEST_CASE("fail ota for sha mismatch", "[ota]") 163 | { 164 | test_require_wifi(); 165 | ota_config_t ota_config; 166 | memcpy(&ota_config, &ota_test_config, sizeof(ota_config_t)); 167 | ota_config.index_uri = "https://openairproject.com/ota/test/index-sha-mismatch.txt", 168 | ota_config.min_version=oap_version_num(hello_world_info.ver) - 1; //one patch earlier 169 | 170 | int ret = check_ota(&ota_config); 171 | TEST_ASSERT_EQUAL_UINT16(OAP_OTA_ERR_SHA_MISMATCH, ret); 172 | } 173 | 174 | TEST_CASE("fail ota for invalid cert", "[ota]") 175 | { 176 | test_require_wifi(); 177 | //git uses digicert CA, cloud front - comodo CA 178 | ota_config_t ota_config = { 179 | .index_uri = "https://raw.githubusercontent.com/openairproject/sensor-esp32/master/components/ota/test/files/index.txt", 180 | .bin_uri_prefix = "https://raw.githubusercontent.com/openairproject/sensor-esp32/master/components/ota/test/files/" 181 | }; 182 | 183 | ota_config.min_version=oap_version_num(hello_world_info.ver) - 1; //one patch earlier 184 | 185 | int ret = check_ota(&ota_config); 186 | TEST_ASSERT_EQUAL_UINT16(OAP_OTA_ERR_REQUEST_FAILED, ret); 187 | } 188 | -------------------------------------------------------------------------------- /components/oap-thingspk/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # -------------------------------------------------------------------------------- /components/oap-thingspk/include/thing_speak.h: -------------------------------------------------------------------------------- 1 | /* 2 | * http.h 3 | * 4 | * Created on: Feb 6, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_THING_SPEAK_H_ 24 | #define COMPONENTS_THING_SPEAK_H_ 25 | 26 | #include "esp_err.h" 27 | #include "oap_publisher.h" 28 | 29 | 30 | oap_publisher_t thingspeak_publisher; 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /components/oap-thingspk/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-thingspk/test/test_thing_speak.c: -------------------------------------------------------------------------------- 1 | /* 2 | * test_thing_speak.c 3 | * 4 | * Created on: Oct 1, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "thing_speak.h" 24 | #include "oap_test.h" 25 | 26 | #define TEST_API_KEY "QMN6JJM996QXBORX" 27 | 28 | TEST_CASE("publish to thingspeak", "[tspk]") { 29 | test_require_wifi(); 30 | 31 | cJSON* cfg = cJSON_CreateObject(); 32 | cJSON_AddNumberToObject(cfg, "enabled", 1); 33 | cJSON_AddStringToObject(cfg, "apikey", TEST_API_KEY); 34 | 35 | TEST_ESP_OK(thingspeak_publisher.configure(cfg)); 36 | cJSON_Delete(cfg); 37 | 38 | pm_data_t pm = { 39 | .pm1_0 = 10, 40 | .pm2_5 = 25, 41 | .pm10 = 50, 42 | .sensor_idx = 0 43 | }; 44 | 45 | pm_data_t pm_aux = { 46 | .pm1_0 = 11, 47 | .pm2_5 = 26, 48 | .pm10 = 51, 49 | .sensor_idx = 1 50 | }; 51 | 52 | env_data_t env = { 53 | .temp = 15.5, 54 | .pressure = 999.9, 55 | .humidity = 79.11, 56 | .sensor_idx = 0 57 | }; 58 | 59 | env_data_t env_int = { 60 | .temp = 22.1, 61 | .pressure = 997.9, 62 | .humidity = 43.89, 63 | .sensor_idx = 1 64 | }; 65 | 66 | oap_measurement_t meas = { 67 | .pm = &pm, 68 | .pm_aux = &pm_aux, 69 | .env = &env, 70 | .env_int = &env_int, 71 | .local_time = 1505156826 72 | }; 73 | 74 | oap_sensor_config_t sensor_config = { 75 | .0 76 | }; 77 | 78 | size_t curr_heap = 0; 79 | size_t prev_heap = 0; 80 | 81 | /* 82 | * heap consumption goes to 0 after ~10 requests 83 | * warning - thingspeak cuts off abusive devices after a while 84 | */ 85 | for (int i = 0; i < 1; i++) { 86 | curr_heap = xPortGetFreeHeapSize(); 87 | ESP_LOGW("test", "REQUEST %d (heap %u, %d bytes)", i, curr_heap, curr_heap-prev_heap); 88 | prev_heap = curr_heap; 89 | TEST_ESP_OK(thingspeak_publisher.publish(&meas, &sensor_config)); 90 | if (i) test_delay(1000); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /components/oap-thingspk/thing_speak.c: -------------------------------------------------------------------------------- 1 | /* 2 | * http.c 3 | * 4 | * Created on: Feb 6, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "thing_speak.h" 24 | 25 | #include "oap_common.h" 26 | #include "oap_storage.h" 27 | #include "oap_debug.h" 28 | #include "esp_request.h" 29 | #include "bootwifi.h" 30 | 31 | //to use https we'd need to install CA cert first. 32 | #define OAP_THING_SPEAK_URI "http://api.thingspeak.com/update" 33 | 34 | static const char *TAG = "thingspk"; 35 | 36 | static char* apikey = NULL; 37 | static int _configured = 0; 38 | 39 | static void set_config_str_field(char** field, char* value) { 40 | if (*field) { 41 | free(*field); 42 | } 43 | *field = str_dup(value); 44 | } 45 | 46 | static char* prepare_thingspeak_payload(oap_measurement_t* meas) { 47 | char* payload = malloc(512); 48 | if (!payload) return NULL; 49 | sprintf(payload, "api_key=%s", apikey); 50 | 51 | if (meas->pm) { 52 | sprintf(payload, "%s&field1=%d&field2=%d&field3=%d", payload, 53 | meas->pm->pm1_0, 54 | meas->pm->pm2_5, 55 | meas->pm->pm10); 56 | } 57 | 58 | if (meas->env) { 59 | sprintf(payload, "%s&field4=%.2f&field5=%.2f&field6=%.2f", payload, 60 | meas->env->temp, 61 | meas->env->pressure, 62 | meas->env->humidity); 63 | } 64 | 65 | //memory metrics 66 | sprintf(payload, "%s&field7=%d&field8=%d", payload, 67 | avg_free_heap_size(), 68 | xPortGetMinimumEverFreeHeapSize()); 69 | 70 | return payload; 71 | } 72 | 73 | static esp_err_t rest_post(char* uri, char* payload) { 74 | request_t* req = req_new(uri); 75 | if (!req) { 76 | return ESP_FAIL; 77 | } 78 | ESP_LOGD(TAG, "request payload: %s", payload); 79 | 80 | req_setopt(req, REQ_SET_POSTFIELDS, payload); 81 | req_setopt(req, REQ_SET_HEADER, HTTP_HEADER_CONNECTION_CLOSE); 82 | 83 | int response_code = req_perform(req); 84 | req_clean(req); 85 | if (response_code == 200) { 86 | ESP_LOGI(TAG, "update succeeded"); 87 | return ESP_OK; 88 | } else { 89 | ESP_LOGW(TAG, "update failed (response code: %d)", response_code); 90 | return ESP_FAIL; 91 | } 92 | 93 | } 94 | 95 | static esp_err_t thing_speak_configure(cJSON* thingspeak) { 96 | _configured = 0; 97 | if (!thingspeak) { 98 | ESP_LOGI(TAG, "config not found"); 99 | return ESP_FAIL; 100 | } 101 | 102 | cJSON* field; 103 | if (!(field = cJSON_GetObjectItem(thingspeak, "enabled")) || !field->valueint) { 104 | ESP_LOGI(TAG, "client disabled"); 105 | return ESP_FAIL; 106 | } 107 | 108 | if ((field = cJSON_GetObjectItem(thingspeak, "apikey")) && field->valuestring) { 109 | set_config_str_field(&apikey, field->valuestring); 110 | } else { 111 | ESP_LOGW(TAG, "apikey not configured"); 112 | return ESP_FAIL; 113 | } 114 | 115 | _configured = 1; 116 | return ESP_OK; 117 | } 118 | 119 | static esp_err_t thing_speak_send(oap_measurement_t* meas, oap_sensor_config_t* oap_sensor_config) { 120 | if (!_configured) { 121 | ESP_LOGE(TAG, "thingspeak not configured"); 122 | return ESP_FAIL; 123 | } 124 | esp_err_t ret; 125 | if ((ret = wifi_connected_wait_for(5000)) != ESP_OK) { 126 | ESP_LOGW(TAG, "no connectivity, skip"); 127 | return ret; 128 | } 129 | 130 | char* payload = prepare_thingspeak_payload(meas); 131 | if (payload) { 132 | esp_err_t ret = rest_post(OAP_THING_SPEAK_URI, payload); 133 | free(payload); 134 | return ret; 135 | } else { 136 | return ESP_FAIL; 137 | } 138 | } 139 | 140 | oap_publisher_t thingspeak_publisher = { 141 | .name = "ThingSpeak", 142 | .configure = thing_speak_configure, 143 | .publish = &thing_speak_send 144 | }; 145 | -------------------------------------------------------------------------------- /components/oap-wifi/Kconfig: -------------------------------------------------------------------------------- 1 | menu "OAP WIFI" 2 | 3 | config OAP_AP_PASSWORD 4 | string "AccessPoint password" 5 | default "cleanair" 6 | help 7 | Password to authenticate to WiFi Access Point when sensor runs in this mode. 8 | Minimum 8 characters. 9 | 10 | endmenu -------------------------------------------------------------------------------- /components/oap-wifi/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | COMPONENT_EMBED_TXTFILES := index.html -------------------------------------------------------------------------------- /components/oap-wifi/cpanel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * cpanel.c 3 | * 4 | * Created on: Oct 5, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "oap_common.h" 24 | #include "mongoose.h" 25 | #include "cJSON.h" 26 | #include "oap_storage.h" 27 | 28 | #define tag "cpanel" 29 | 30 | extern const uint8_t index_html_start[] asm("_binary_index_html_start"); 31 | extern const uint8_t index_html_end[] asm("_binary_index_html_end"); 32 | 33 | static char *mgStrToStr(struct mg_str mgStr) { 34 | char *retStr = (char *) malloc(mgStr.len + 1); 35 | memcpy(retStr, mgStr.p, mgStr.len); 36 | retStr[mgStr.len] = 0; 37 | return retStr; 38 | } // mgStrToStr 39 | 40 | static void handler_index(struct mg_connection *nc) { 41 | size_t resp_size = index_html_end-index_html_start; 42 | mg_send_head(nc, 200, resp_size, "Content-Type: text/html"); 43 | mg_send(nc, index_html_start, resp_size); 44 | ESP_LOGD(tag, "served %d bytes", resp_size); 45 | } 46 | 47 | static void handler_get_config(struct mg_connection *nc, struct http_message *message) { 48 | ESP_LOGD(tag, "handler_get_config"); 49 | cJSON* config = storage_get_config_to_update(); 50 | char* json = cJSON_Print(config); 51 | char* headers = malloc(200); 52 | sprintf(headers, "Content-Type: application/json\r\nX-Version: %s", oap_version_str()); 53 | mg_send_head(nc, 200, strlen(json), headers); 54 | mg_send(nc, json, strlen(json)); 55 | free(headers); 56 | free(json); 57 | } 58 | 59 | static void handler_reboot(struct mg_connection *nc) { 60 | mg_send_head(nc, 200, 0, "Content-Type: text/plain"); 61 | oap_reboot("requested by user"); 62 | } 63 | 64 | static void handler_set_config(struct mg_connection *nc, struct http_message *message) { 65 | ESP_LOGD(tag, "handler_set_config"); 66 | char *body = mgStrToStr(message->body); 67 | cJSON* config = cJSON_Parse(body); 68 | free(body); 69 | if (config) { 70 | storage_update_config(config); 71 | handler_get_config(nc, message); 72 | } else { 73 | mg_http_send_error(nc, 500, "invalid config"); 74 | } 75 | cJSON_Delete(config); 76 | } 77 | 78 | /** 79 | * Handle mongoose events. These are mostly requests to process incoming 80 | * browser requests. The ones we handle are: 81 | * GET / - Send the enter details page. 82 | * GET /set - Set the connection info (REST request). 83 | * POST /ssidSelected - Set the connection info (HTML FORM). 84 | */ 85 | void cpanel_event_handler(struct mg_connection *nc, int ev, void *evData) { 86 | ESP_LOGV(tag, "- Event: %d", ev); 87 | uint8_t handled = 0; 88 | switch (ev) { 89 | case MG_EV_HTTP_REQUEST: { 90 | struct http_message *message = (struct http_message *) evData; 91 | 92 | //mg_str is not terminated with '\0' 93 | char *uri = mgStrToStr(message->uri); 94 | char *method = mgStrToStr(message->method); 95 | 96 | ESP_LOGD(tag, "%s %s", method, uri); 97 | 98 | if (strcmp(uri, "/") == 0) { 99 | handler_index(nc); 100 | handled = 1; 101 | } 102 | if (strcmp(uri, "/reboot") == 0) { 103 | handler_reboot(nc); 104 | handled = 1; 105 | } 106 | if(strcmp(uri, "/config") == 0) { 107 | if (strcmp(method, "GET") == 0) { 108 | handler_get_config(nc, message); 109 | handled = 1; 110 | } else if (strcmp(method, "POST") == 0) { 111 | handler_set_config(nc, message); 112 | handled = 1; 113 | } 114 | } 115 | 116 | if (!handled) { 117 | mg_send_head(nc, 404, 0, "Content-Type: text/plain"); 118 | } 119 | nc->flags |= MG_F_SEND_AND_CLOSE; 120 | free(uri); 121 | free(method); 122 | break; 123 | } 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /components/oap-wifi/cpanel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * cpanel.h 3 | * 4 | * Created on: Oct 5, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_BOOTWIFI_CPANEL_H_ 24 | #define COMPONENTS_BOOTWIFI_CPANEL_H_ 25 | 26 | 27 | #include "mongoose.h" 28 | 29 | void cpanel_event_handler(struct mg_connection *nc, int ev, void *evData); 30 | 31 | 32 | #endif /* COMPONENTS_BOOTWIFI_CPANEL_H_ */ 33 | -------------------------------------------------------------------------------- /components/oap-wifi/include/bootwifi.h: -------------------------------------------------------------------------------- 1 | /* 2 | * bootwifi.h 3 | * 4 | * Created on: Nov 25, 2016 5 | * Author: kolban 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_BOOTWIFI_H_ 24 | #define MAIN_BOOTWIFI_H_ 25 | 26 | #include 27 | #include "cJSON.h" 28 | 29 | #define SSID_SIZE (32) // Maximum SSID size 30 | #define PASSWORD_SIZE (64) // Maximum password size 31 | 32 | typedef void(*wifi_state_callback_f)(bool connected, bool ap_mode); 33 | 34 | typedef struct { 35 | char ssid[SSID_SIZE]; 36 | char password[PASSWORD_SIZE]; 37 | tcpip_adapter_ip_info_t ipInfo; // Optional static IP information 38 | int ap_mode; 39 | int control_panel; 40 | wifi_state_callback_f callback; 41 | } oc_wifi_t; 42 | 43 | 44 | 45 | esp_err_t wifi_configure(cJSON* wifi, wifi_state_callback_f wifi_state_callback); 46 | void wifi_boot(); 47 | esp_err_t wifi_connected_wait_for(uint32_t ms); 48 | esp_err_t wifi_ap_started_wait_for(uint32_t ms); 49 | esp_err_t wifi_disconnected_wait_for(uint32_t ms); 50 | 51 | 52 | 53 | #endif /* MAIN_BOOTWIFI_H_ */ 54 | -------------------------------------------------------------------------------- /components/oap-wifi/include/server_cpanel.h: -------------------------------------------------------------------------------- 1 | /* 2 | * server_cpanel.h 3 | * 4 | * Created on: Oct 5, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_BOOTWIFI_INCLUDE_SERVER_CPANEL_H_ 24 | #define COMPONENTS_BOOTWIFI_INCLUDE_SERVER_CPANEL_H_ 25 | 26 | #include 27 | 28 | void cpanel_wifi_handler(bool connected, bool ap_mode); 29 | 30 | 31 | #endif /* COMPONENTS_BOOTWIFI_INCLUDE_SERVER_CPANEL_H_ */ 32 | -------------------------------------------------------------------------------- /components/oap-wifi/server.c: -------------------------------------------------------------------------------- 1 | /* 2 | * server.c 3 | * 4 | * Created on: Oct 4, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "server.h" 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "esp_err.h" 29 | #include "oap_common.h" 30 | 31 | #define tag "serv" 32 | 33 | typedef enum { 34 | NOT_RUN = 0, 35 | IDLE, 36 | RUNNING, 37 | RESTARTING 38 | } server_mode_t; 39 | 40 | extern int mg_invalid_socket; 41 | 42 | static server_mode_t mode = NOT_RUN; 43 | 44 | /* 45 | char *mongoose_eventToString(int ev) { 46 | static char temp[100]; 47 | switch (ev) { 48 | case MG_EV_CONNECT: 49 | return "MG_EV_CONNECT"; 50 | case MG_EV_ACCEPT: 51 | return "MG_EV_ACCEPT"; 52 | case MG_EV_CLOSE: 53 | return "MG_EV_CLOSE"; 54 | case MG_EV_SEND: 55 | return "MG_EV_SEND"; 56 | case MG_EV_RECV: 57 | return "MG_EV_RECV"; 58 | case MG_EV_HTTP_REQUEST: 59 | return "MG_EV_HTTP_REQUEST"; 60 | case MG_EV_MQTT_CONNACK: 61 | return "MG_EV_MQTT_CONNACK"; 62 | case MG_EV_MQTT_CONNACK_ACCEPTED: 63 | return "MG_EV_MQTT_CONNACK"; 64 | case MG_EV_MQTT_CONNECT: 65 | return "MG_EV_MQTT_CONNECT"; 66 | case MG_EV_MQTT_DISCONNECT: 67 | return "MG_EV_MQTT_DISCONNECT"; 68 | case MG_EV_MQTT_PINGREQ: 69 | return "MG_EV_MQTT_PINGREQ"; 70 | case MG_EV_MQTT_PINGRESP: 71 | return "MG_EV_MQTT_PINGRESP"; 72 | case MG_EV_MQTT_PUBACK: 73 | return "MG_EV_MQTT_PUBACK"; 74 | case MG_EV_MQTT_PUBCOMP: 75 | return "MG_EV_MQTT_PUBCOMP"; 76 | case MG_EV_MQTT_PUBLISH: 77 | return "MG_EV_MQTT_PUBLISH"; 78 | case MG_EV_MQTT_PUBREC: 79 | return "MG_EV_MQTT_PUBREC"; 80 | case MG_EV_MQTT_PUBREL: 81 | return "MG_EV_MQTT_PUBREL"; 82 | case MG_EV_MQTT_SUBACK: 83 | return "MG_EV_MQTT_SUBACK"; 84 | case MG_EV_MQTT_SUBSCRIBE: 85 | return "MG_EV_MQTT_SUBSCRIBE"; 86 | case MG_EV_MQTT_UNSUBACK: 87 | return "MG_EV_MQTT_UNSUBACK"; 88 | case MG_EV_MQTT_UNSUBSCRIBE: 89 | return "MG_EV_MQTT_UNSUBSCRIBE"; 90 | case MG_EV_WEBSOCKET_HANDSHAKE_REQUEST: 91 | return "MG_EV_WEBSOCKET_HANDSHAKE_REQUEST"; 92 | case MG_EV_WEBSOCKET_HANDSHAKE_DONE: 93 | return "MG_EV_WEBSOCKET_HANDSHAKE_DONE"; 94 | case MG_EV_WEBSOCKET_FRAME: 95 | return "MG_EV_WEBSOCKET_FRAME"; 96 | } 97 | sprintf(temp, "Unknown event: %d", ev); 98 | return temp; 99 | }*/ 100 | 101 | 102 | static esp_err_t main_loop(void *mongoose_event_handler) { 103 | struct mg_mgr mgr; 104 | struct mg_connection *connection; 105 | 106 | ESP_LOGD(tag, ">> main_loop"); 107 | mg_mgr_init(&mgr, NULL); 108 | 109 | connection = mg_bind(&mgr, ":80", mongoose_event_handler); 110 | 111 | if (connection == NULL) { 112 | //when this happens usually it won't recover until it gets a new IP 113 | //maybe we should reboot? 114 | ESP_LOGW(tag, "No connection from the mg_bind()."); 115 | mg_mgr_free(&mgr); 116 | return ESP_FAIL; 117 | } 118 | //use http 119 | mg_set_protocol_http_websocket(connection); 120 | 121 | mg_invalid_socket=0; //hack for corrupted mongoose sockets (AP mode + http request triggers it) 122 | while (mode == RUNNING && !mg_invalid_socket) { 123 | mg_mgr_poll(&mgr, 1000); 124 | } 125 | 126 | mg_mgr_free(&mgr); 127 | ESP_LOGD(tag, "<< main_loop"); 128 | return ESP_OK; 129 | } 130 | 131 | static void server_task(void *mongoose_event_handler) { 132 | ESP_LOGD(tag, "start"); 133 | while (1) { 134 | switch (mode) { 135 | case RUNNING: 136 | if (main_loop(mongoose_event_handler) != ESP_OK) { 137 | vTaskDelay(1000 / portTICK_PERIOD_MS); 138 | } 139 | break; 140 | case IDLE: 141 | vTaskDelay(1000 / portTICK_PERIOD_MS); 142 | break; 143 | default: //{RESTARTING,NOT_RUN} => RUNNING 144 | mode = RUNNING; 145 | } 146 | } 147 | vTaskDelete(NULL); 148 | } 149 | 150 | void server_restart() { 151 | ESP_LOGD(tag, "restart"); 152 | mode = RESTARTING; 153 | } 154 | 155 | void server_stop() { 156 | ESP_LOGD(tag, "idle"); 157 | mode = IDLE; 158 | } 159 | 160 | void server_start(void *event_handler) { 161 | if (mode == NOT_RUN) { 162 | mode = RUNNING; 163 | xTaskCreatePinnedToCore(&server_task, "mongoose_task", 10000, event_handler, DEFAULT_TASK_PRIORITY+1, NULL, 0); 164 | } else { 165 | server_restart(); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /components/oap-wifi/server.h: -------------------------------------------------------------------------------- 1 | /* 2 | * server.h 3 | * 4 | * Created on: Oct 4, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef COMPONENTS_BOOTWIFI_SERVER_H_ 24 | #define COMPONENTS_BOOTWIFI_SERVER_H_ 25 | 26 | #include "mongoose.h" 27 | 28 | void server_restart(); 29 | void server_stop(); 30 | void server_start(void *event_handler); 31 | 32 | 33 | 34 | #endif /* COMPONENTS_BOOTWIFI_SERVER_H_ */ 35 | -------------------------------------------------------------------------------- /components/oap-wifi/server_cpanel.c: -------------------------------------------------------------------------------- 1 | /* 2 | * server_cpanel.c 3 | * 4 | * Created on: Oct 5, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "server_cpanel.h" 24 | #include "server.h" 25 | #include "cpanel.h" 26 | 27 | void cpanel_wifi_handler(bool connected, bool ap_mode) { 28 | if (connected) { 29 | server_start(cpanel_event_handler); 30 | } else { 31 | server_restart(); 32 | } 33 | } 34 | 35 | 36 | -------------------------------------------------------------------------------- /components/oap-wifi/test/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | #Component Makefile 3 | # 4 | 5 | COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive 6 | -------------------------------------------------------------------------------- /components/oap-wifi/test/test_bootwifi.c: -------------------------------------------------------------------------------- 1 | /* 2 | * oap_test.c 3 | * 4 | * Created on: Sep 11, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #include "oap_test.h" 24 | #include "bootwifi.h" 25 | #include "oap_storage.h" 26 | #include "esp_wifi.h" 27 | #include "server_cpanel.h" 28 | #include "esp_request.h" 29 | 30 | 31 | TEST_CASE("test wifi STA","[wifi]") { 32 | test_require_wifi(); 33 | } 34 | 35 | /* 36 | * this test is problematic because esp32 encounters issues after switching back from AP to STA. 37 | * sometimes after this transition, a few ssl requests fail and then it recovers (cache?) 38 | * run it as a second to last one, and as last - do 'reconnect wifi' 39 | */ 40 | TEST_CASE("test wifi AP","[wifi]") { 41 | //TEST_IGNORE(); 42 | test_require_ap(); 43 | } 44 | 45 | //TEST_CASE("test cpanel in AP","[wifi]") { 46 | // test_require_ap_with(cpanel_wifi_handler); 47 | // 48 | // test_delay(1000); 49 | // request_t* r = req_new("http://www.google.com"); //this breaks mongoose socket 50 | // req_perform(r); 51 | // req_clean(r); 52 | // 53 | // test_delay(10000); 54 | //} 55 | 56 | // this test is unstable - sometimes it reconnects before we're able to detect disconnect 57 | // 58 | //TEST_CASE("reconnect wifi","[wifi]") { 59 | // test_require_wifi(); 60 | // esp_wifi_stop(); 61 | // TEST_ESP_OK(wifi_disconnected_wait_for(5000)); 62 | // TEST_ESP_OK(wifi_connected_wait_for(10000)); 63 | //} 64 | -------------------------------------------------------------------------------- /doc/BST-BME280_DS001-10.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/doc/BST-BME280_DS001-10.pdf -------------------------------------------------------------------------------- /doc/BST-BMP280-DS001-11.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/doc/BST-BMP280-DS001-11.pdf -------------------------------------------------------------------------------- /doc/api/README.md: -------------------------------------------------------------------------------- 1 | ## Architecture 2 | 3 | OAP is built on the top of AWS Iot. 4 | 5 | Each sensor is identified by a unique name. 6 | 7 | Senors can connect with OAP via REST or MQTT. 8 | Connections are secured and authentication is performed based on certificate issued by OAP when new sensor gets registered. 9 | 10 | Once connected, sensor can update its **state** (represented as a JSON tree) in the OAP cloud by sending json **state-reported** message. 11 | It can also receive **state-desired** requests from OAP, this feature however is fully optional and can be used to remotely change current configuration of connected sensors. 12 | 13 | ## Sensor API 14 | 15 | State itself has no particular schema and no validation is performed - it can be any value you want to persist in OAP cloud. 16 | However, to create a record in OAP result tables (and therefore - publish the results), state-reported message has to meet some conditions and contain at least 'result.uid' field. 17 | 18 | { 19 | "state" : { 20 | "reported" : { 21 | /** 22 | * All parameters below ARE OPTIONAL. 23 | * Thing shadow will get updated with any values posted here (there's no validation), 24 | * however system will record a measurement only when some specifics conditions are met. See below. 25 | */ 26 | 27 | /** 28 | * local time of measurement in epoch seconds. 29 | * if this value is present, it is different than previously recorded and it falls into valid range, server will accept 30 | * this as a time of measurement. Otherwise server time will be used. 31 | * This field enables you to report historical measurements (for example taken when sensor is offline) - but only 32 | * if your sensor is equipped with Real-Time Clock. 33 | */ 34 | "localTime" : 0, 35 | 36 | "results" : { 37 | /** 38 | * this parameter is required for server to accept incoming data as a measurement. 39 | * if this value is missing (or null, undefined, 0 or empty string) or equal to previously sent uid, 40 | * thing shadow will get updated but result tables will not. 41 | */ 42 | "uid" : 1, 43 | /** 44 | * pollution results. all parameters are optional but when present, types must match. 45 | * if particular parameter is missing, but was reported previously - the old value will be taken. 46 | */ 47 | "pm" : { 48 | "pm1_0" : 0, 49 | "pm2_5" : 0, 50 | "pm10" : 0, 51 | 52 | /* 53 | * this parameter determines sensor used for measurement. used by meters with multiple PM sensors. 54 | */ 55 | "sensor" : 0 56 | }, 57 | /** 58 | * measured atmospheric conditions. parameters are optional but types are validated. 59 | */ 60 | "weather" : { 61 | "temp" : 0.0, 62 | "pressure" : 0.0, 63 | "humidity" : 0.0, 64 | "sensor" : 0 65 | } 66 | }, 67 | /** 68 | * current configuration of the sensor. 69 | */ 70 | "config" : { 71 | /** 72 | * sent it when sensor changed its location from outdoor to indoor or vice-versa. 73 | */ 74 | "indoor" : false, 75 | /** 76 | * any value other than 0 means that sensor is running in test mode and results should be ignored from main metrics. 77 | */ 78 | "test" : 0, 79 | /** 80 | * optional location data for mobile sensors 81 | */ 82 | "location" : { 83 | "lat" : 0.0, 84 | "lng" : 0.0 85 | } 86 | } 87 | } 88 | } 89 | } 90 | 91 | ## Data API 92 | 93 | Results are currently stored in three DynamoDB tables: 94 | 95 | 1. OAP_ALL (all recorded measurements) 96 | 2. OAP_HOUR (one measurement per hour) 97 | 3. OAP_LAST (last recorded measurement) 98 | 99 | All registered sensors are listed in OAP_THINGS table. 100 | Anonymous users have read-only access to these tables and can use them via DynamoDB AWS-SDK api. 101 | 102 | -------------------------------------------------------------------------------- /doc/api/state.json: -------------------------------------------------------------------------------- 1 | { 2 | "state" : { 3 | "reported" : { 4 | /** 5 | * All parameters below ARE OPTIONAL. 6 | * Thing shadow will get updated with any values posted here (there's no validation), 7 | * however system will record a measurement only when some specifics conditions are met. See below. 8 | */ 9 | 10 | /** 11 | * local time of measurement in epoch seconds. 12 | * if this value is present, it is different than previously recorded and it falls into valid range, server will accept 13 | * this as a time of measurement. Otherwise server time will be used. 14 | * This field enables you to report historical measurements (for example taken when sensor is offline) - but only 15 | * if your sensor is equipped with Real-Time Clock. 16 | */ 17 | "localTime" : 0, 18 | 19 | "results" : { 20 | /** 21 | * this parameter is required for server to accept incoming data as a measurement. 22 | * if this value is missing (or null, undefined, 0 or empty string) or equal to previously sent uid, 23 | * thing shadow will get updated but result tables will not. 24 | */ 25 | "uid" : 1, 26 | /** 27 | * pollution results. all parameters are optional but when present, types must match. 28 | * if particular parameter is missing, but was reported previously - the old value will be taken. 29 | */ 30 | "pm" : { 31 | "pm1_0" : 0, 32 | "pm2_5" : 0, 33 | "pm10" : 0, 34 | 35 | /* 36 | * this parameter determines sensor used for measurement. used by meters with multiple PM sensors. 37 | */ 38 | "sensor" : 0 39 | }, 40 | 41 | /** 42 | * optional results for the second sensor, if both were used to perform measurement at the same time 43 | */ 44 | "pmAux": { 45 | "pm1_0" : 0, 46 | "pm2_5" : 0, 47 | "pm10" : 0, 48 | "sensor": 1 49 | }, 50 | 51 | /** 52 | * measured atmospheric conditions. parameters are optional but types are validated. 53 | */ 54 | "weather" : { 55 | "temp" : 0.0, 56 | "pressure" : 0.0, 57 | "humidity" : 0.0, 58 | "sensor" : 0 59 | }, 60 | 61 | /** 62 | * measured internal atmospheric conditions (optional) 63 | */ 64 | "weather" : { 65 | "temp" : 0.0, 66 | "pressure" : 0.0, 67 | "humidity" : 0.0, 68 | "sensor" : 0 69 | } 70 | }, 71 | /** 72 | * current configuration of the sensor. 73 | */ 74 | "config" : { 75 | /** 76 | * sent it when sensor changed its location from outdoor to indoor or vice-versa. 77 | */ 78 | "indoor" : false, 79 | /** 80 | * any value other than 0 means that sensor is running in test mode and results should be ignored from main metrics. 81 | */ 82 | "test" : 0, 83 | /** 84 | * optional location data for mobile sensors 85 | */ 86 | "location" : { 87 | "lat" : 0.0, 88 | "lng" : 0.0 89 | } 90 | } 91 | } 92 | } 93 | } -------------------------------------------------------------------------------- /doc/images/ESP32-DevBoard.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/doc/images/ESP32-DevBoard.jpg -------------------------------------------------------------------------------- /doc/images/prototype.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/doc/images/prototype.jpg -------------------------------------------------------------------------------- /doc/images/schema.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/doc/images/schema.jpg -------------------------------------------------------------------------------- /doc/images/sensor_settings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/doc/images/sensor_settings.png -------------------------------------------------------------------------------- /doc/plantower-pms5003-manual_v2-3.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/openairproject/sensor-esp32/374e28ed91679678e267c937e63ae3dcc64d7818/doc/plantower-pms5003-manual_v2-3.pdf -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "OpenAirProject" 2 | 3 | config OAP_CONTROL_PANEL 4 | int "enable control panel" 5 | default 1 6 | help 7 | Enable web-based control panel where you can configure various parameters of the sensor, 8 | including wifi and data publishing settings 9 | 10 | endmenu -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Main component makefile. 3 | # 4 | # This Makefile can be left empty. By default, it will take the sources in the 5 | # src/ directory, compile them and link them into lib(subdirectory_name).a 6 | # in the build directory. This behaviour is entirely configurable, 7 | # please read the ESP-IDF documents if you need to do this. 8 | # 9 | 10 | # TODO split into proper components 11 | #COMPONENT_PRIV_INCLUDEDIRS := . 12 | #COMPONENT_SRCDIRS := . bootwifi mongoose hardware net 13 | 14 | CFLAGS += -DCS_PLATFORM=CS_P_ESP32 \ 15 | -DMG_DISABLE_DIRECTORY_LISTING=1 \ 16 | -DMG_DISABLE_DAV=1 \ 17 | -DMG_DISABLE_CGI=1 \ 18 | -DMG_DISABLE_FILESYSTEM=1 \ 19 | -DMG_LWIP=1 \ 20 | -DMG_ENABLE_BROADCAST \ 21 | -DMBEDTLS_DEBUG_C=1 22 | -------------------------------------------------------------------------------- /main/oap_config.txt: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 3 | * 4 | * Created on: Feb 9, 2017 5 | * Author: kris 6 | * 7 | * This file is part of OpenAirProject-ESP32. 8 | * 9 | * OpenAirProject-ESP32 is free software: you can redistribute it and/or modify 10 | * it under the terms of the GNU General Public License as published by 11 | * the Free Software Foundation, either version 3 of the License, or 12 | * (at your option) any later version. 13 | * 14 | * OpenAirProject-ESP32 is distributed in the hope that it will be useful, 15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 | * GNU General Public License for more details. 18 | * 19 | * You should have received a copy of the GNU General Public License 20 | * along with OpenAirProject-ESP32. If not, see . 21 | */ 22 | 23 | #ifndef MAIN_CONFIG_H_ 24 | #define MAIN_CONFIG_H_ 25 | 26 | /* 27 | * the hardware configuration was tested on official ESP32 DevKit (with WROOM32 module). 28 | * For other boards pin assignments may require changes. 29 | */ 30 | 31 | 32 | /* ------------------------------------------------------- 33 | * PM SENSOR 34 | */ 35 | 36 | /* 37 | * UART configuration. Do not use UART0 38 | */ 39 | //#define OAP_PM_UART_NUM UART_NUM_1 40 | // 41 | //#define OAP_PM_UART_RXD_PIN (34) //this pin can be R/O (>=34) . we care only about RX 42 | //#define OAP_PM_UART_TXD_PIN (4) //any free 'safe' pin 43 | //#define OAP_PM_UART_RTS_PIN (18) //any free 'safe' pin 44 | //#define OAP_PM_UART_CTS_PIN (19) //any free 'safe' pin 45 | 46 | /* 47 | * pmsX003 sensor need to know whether it is outdoor or indoor 48 | * to compensate values 49 | */ 50 | //#define OAP_PM_SENSOR_OUTDOOR 0 51 | 52 | /* 53 | * output GPIO pin to enable/disable PM sensor. 54 | * same pins that work with LEDC are ok. 55 | */ 56 | //#define OAP_PM_SENSOR_CONTROL_PIN (10) 57 | 58 | /* 59 | * max number of samples to compute average from during measurement 60 | * sampling interval is ~1sec, so for measurement times > 2min you might want to increase this number 61 | * (otherwise earlier samples will be overridden) 62 | */ 63 | //#define OAP_PM_SAMPLE_BUF_SIZE 120 64 | 65 | 66 | 67 | 68 | /* ------------------------------------------------------- 69 | * BMx280 SENSOR 70 | */ 71 | 72 | /* 73 | * be careful with choosing gpio. i2c pin must be R/W (<34) 74 | * 75 | * so far I've tested: 76 | * safe pins: 25,26,27,14,10 77 | * problems : 78 | * 12 =>Warning: Could not auto-detect Flash size (FlashID=0xffffff, SizeID=0xff), defaulting to 4MB \nFlash params set to 0x0220 79 | * 32,33 => (i2c err) 80 | * 13,11 => (i2c err) 81 | * 9 => (rebooting) Guru Meditation Error of type IllegalInstruction occurred on core 0. Exception was unhandled 82 | */ 83 | 84 | 85 | 86 | /* ------------------------------------------------------- 87 | * CONTROL BUTTON(S) 88 | */ 89 | 90 | /* 91 | * we're good with most pins here, even those that do not work with LEDC/IC2 (32, 33) 92 | */ 93 | //#define OAP_BTN_0_PIN (35) 94 | //#define OAP_BTN_1_PIN (33) 95 | 96 | 97 | /* ------------------------------------------------------- 98 | * RGB LED 99 | */ 100 | 101 | /* 102 | * careful with choosing gpio... 103 | * safe: 12,14,27 104 | * problems: 9,11 - reboots 105 | */ 106 | //#define OAP_LED_PINS 12,27,14 107 | 108 | 109 | /* ------------------------------------------------------- 110 | * THING SPEAK CLIENT 111 | */ 112 | //#define OAP_THING_SPEAK_API_KEY "" 113 | 114 | //#define OAP_RESULT_BUFFER_SIZE 100 115 | 116 | #endif /* MAIN_CONFIG_H_ */ 117 | 118 | -------------------------------------------------------------------------------- /partitions.csv: -------------------------------------------------------------------------------- 1 | # Name, Type, SubType, Offset, Size 2 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 3 | nvs, data, nvs, 0x9000, 0x13000 4 | otadata, data, ota, 0x1c000, 0x2000 5 | phy_init, data, phy, 0x1e000, 0x1000 6 | factory, 0, 0, 0x30000, 0x140000 7 | coredump, data, coredump,, 0x10000 8 | ota_0, 0, ota_0, , 0x140000 9 | ota_1, 0, ota_1, , 0x140000 -------------------------------------------------------------------------------- /unit-test-app/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | sdkconfig 3 | sdkconfig.old 4 | .DS_Store 5 | main/*.bak 6 | core.dat 7 | -------------------------------------------------------------------------------- /unit-test-app/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := unit-test-app 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | 10 | print_flash_cmd: 11 | echo $(ESPTOOL_WRITE_FLASH_OPTIONS) $(ESPTOOL_ALL_FLASH_ARGS) | sed -e 's:'$(PWD)/build/'::g' 12 | -------------------------------------------------------------------------------- /unit-test-app/README.md: -------------------------------------------------------------------------------- 1 | # Unit Test App 2 | 3 | ESP-IDF unit tests are run using Unit Test App. The app can be built with the unit tests for a specific component. Unit tests are in `test` subdirectories of respective components. 4 | 5 | # Building Unit Test App 6 | 7 | * Follow the setup instructions in the top-level esp-idf README. 8 | * Set IDF_PATH environment variable to point to the path to the esp-idf top-level directory. 9 | * Change into `tools/unit-test-app` directory 10 | * `make menuconfig` to configure the Unit Test App. 11 | * `make TEST_COMPONENTS=` with `TEST_COMPONENTS` set to names of the components to be included in the test app. Or `make TESTS_ALL=1` to build the test app with all the tests for components having `test` subdirectory. 12 | * Follow the printed instructions to flash, or run `make flash`. 13 | 14 | # Running Unit Tests 15 | 16 | The unit test loader will prompt by showing a menu of available tests to run: 17 | 18 | * Type a number to run a single test. 19 | * `*` to run all tests. 20 | * `[tagname]` to run tests with "tag" 21 | * `![tagname]` to run tests without "tag" (`![ignore]` is very useful as it runs all CI-enabled tests.) 22 | * `"test name here"` to run test with given name 23 | -------------------------------------------------------------------------------- /unit-test-app/components/unity/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # Component Makefile 3 | # 4 | -------------------------------------------------------------------------------- /unit-test-app/components/unity/include/test_utils.h: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | #pragma once 15 | 16 | // Utilities for esp-idf unit tests 17 | 18 | #include 19 | #include 20 | 21 | /* Return the 'flash_test' custom data partition (type 0x55) 22 | defined in the custom partition table. 23 | */ 24 | const esp_partition_t *get_test_data_partition(); 25 | 26 | /** 27 | * @brief Initialize reference clock 28 | * 29 | * Reference clock provides timestamps at constant 1 MHz frequency, even when 30 | * the APB frequency is changing. 31 | */ 32 | void ref_clock_init(); 33 | 34 | /** 35 | * @brief Deinitialize reference clock 36 | */ 37 | void ref_clock_deinit(); 38 | 39 | /** 40 | * @brief Get reference clock timestamp 41 | * @return number of microseconds since the reference clock was initialized 42 | */ 43 | uint64_t ref_clock_get(); 44 | -------------------------------------------------------------------------------- /unit-test-app/components/unity/include/unity_config.h: -------------------------------------------------------------------------------- 1 | #ifndef UNITY_CONFIG_H 2 | #define UNITY_CONFIG_H 3 | 4 | // This file gets included from unity.h via unity_internals.h 5 | // It is inside #ifdef __cplusplus / extern "C" block, so we can 6 | // only use C features here 7 | 8 | // Adapt Unity to our environment, disable FP support 9 | 10 | #include 11 | 12 | /* Some definitions applicable to Unity running in FreeRTOS */ 13 | #define UNITY_FREERTOS_PRIORITY 5 14 | #define UNITY_FREERTOS_CPU 0 15 | 16 | #define UNITY_EXCLUDE_FLOAT 17 | #define UNITY_EXCLUDE_DOUBLE 18 | 19 | #define UNITY_OUTPUT_CHAR unity_putc 20 | #define UNITY_OUTPUT_FLUSH unity_flush 21 | 22 | // Define helpers to register test cases from multiple files 23 | 24 | #define UNITY_EXPAND2(a, b) a ## b 25 | #define UNITY_EXPAND(a, b) UNITY_EXPAND2(a, b) 26 | #define UNITY_TEST_UID(what) UNITY_EXPAND(what, __LINE__) 27 | 28 | #define UNITY_TEST_REG_HELPER reg_helper ## UNITY_TEST_UID 29 | #define UNITY_TEST_DESC_UID desc ## UNITY_TEST_UID 30 | struct test_desc_t 31 | { 32 | const char* name; 33 | const char* desc; 34 | void (*fn)(void); 35 | const char* file; 36 | int line; 37 | struct test_desc_t* next; 38 | }; 39 | 40 | void unity_testcase_register(struct test_desc_t* desc); 41 | 42 | void unity_run_menu(); 43 | 44 | void unity_run_tests_with_filter(const char* filter); 45 | 46 | void unity_run_all_tests(); 47 | 48 | /* Test case macro, a-la CATCH framework. 49 | First argument is a free-form description, 50 | second argument is (by convention) a list of identifiers, each one in square brackets. 51 | Identifiers are used to group related tests, or tests with specific properties. 52 | Use like: 53 | 54 | TEST_CASE("Frobnicator forbnicates", "[frobnicator][rom]") 55 | { 56 | // test goes here 57 | } 58 | */ 59 | #define TEST_CASE(name_, desc_) \ 60 | static void UNITY_TEST_UID(test_func_) (void); \ 61 | static void __attribute__((constructor)) UNITY_TEST_UID(test_reg_helper_) () \ 62 | { \ 63 | static struct test_desc_t UNITY_TEST_UID(test_desc_) = { \ 64 | .name = name_, \ 65 | .desc = desc_, \ 66 | .fn = &UNITY_TEST_UID(test_func_), \ 67 | .file = __FILE__, \ 68 | .line = __LINE__, \ 69 | .next = NULL \ 70 | }; \ 71 | unity_testcase_register( & UNITY_TEST_UID(test_desc_) ); \ 72 | }\ 73 | static void UNITY_TEST_UID(test_func_) (void) 74 | /** 75 | * Note: initialization of test_desc_t fields above has to be done exactly 76 | * in the same order as the fields are declared in the structure. 77 | * Otherwise the initializer will not be valid in C++ (which doesn't 78 | * support designated initializers). G++ can parse the syntax, but 79 | * field names are treated as annotations and don't affect initialization 80 | * order. Also make sure all the fields are initialized. 81 | */ 82 | 83 | // shorthand to check esp_err_t return code 84 | #define TEST_ESP_OK(rc) TEST_ASSERT_EQUAL_HEX32(ESP_OK, rc) 85 | #define TEST_ESP_ERR(err, rc) TEST_ASSERT_EQUAL_HEX32(err, rc) 86 | 87 | 88 | #endif //UNITY_CONFIG_H 89 | -------------------------------------------------------------------------------- /unit-test-app/components/unity/license.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2007-14 Mike Karlesky, Mark VanderVoord, Greg Williams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /unit-test-app/components/unity/test_utils.c: -------------------------------------------------------------------------------- 1 | // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "unity.h" 16 | #include "test_utils.h" 17 | 18 | const esp_partition_t *get_test_data_partition() 19 | { 20 | /* This finds "flash_test" partition defined in partition_table_unit_test_app.csv */ 21 | const esp_partition_t *result = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, 22 | ESP_PARTITION_SUBTYPE_ANY, "flash_test"); 23 | TEST_ASSERT_NOT_NULL(result); /* means partition table set wrong */ 24 | return result; 25 | } 26 | -------------------------------------------------------------------------------- /unit-test-app/main/app_main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "freertos/FreeRTOS.h" 3 | #include "freertos/task.h" 4 | #include "unity.h" 5 | #include "unity_config.h" 6 | #include "oap_test.h" 7 | 8 | void unityTask(void *pvParameters) 9 | { 10 | vTaskDelay(1000 / portTICK_PERIOD_MS); 11 | unity_run_menu(); 12 | while(1); 13 | } 14 | 15 | void app_main() 16 | { 17 | test_reset_hw(); 18 | // Note: if unpinning this task, change the way run times are calculated in 19 | // unity_platform 20 | xTaskCreatePinnedToCore(unityTask, "unityTask", 8192, NULL, 21 | UNITY_FREERTOS_PRIORITY, NULL, UNITY_FREERTOS_CPU); 22 | } 23 | -------------------------------------------------------------------------------- /unit-test-app/main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | -------------------------------------------------------------------------------- /unit-test-app/partition_table_unit_test_app.csv: -------------------------------------------------------------------------------- 1 | # Let's keep it the same as for app 2 | # Name, Type, SubType, Offset, Size 3 | # Note: if you change the phy_init or app partition offset, make sure to change the offset in Kconfig.projbuild 4 | nvs, data, nvs, 0x9000, 0x13000 5 | otadata, data, ota, 0x1c000, 0x2000 6 | phy_init, data, phy, 0x1e000, 0x1000 7 | factory, 0, 0, 0x30000, 0x140000 8 | coredump, data, coredump,, 0x10000 9 | ota_0, 0, ota_0, , 0x140000 10 | ota_1, 0, ota_1, , 0x140000 --------------------------------------------------------------------------------