Merge branch 'development' into prerelease-13.2

This commit is contained in:
Theo Arends 2023-10-16 16:52:59 +02:00
commit 2d97311c5c
883 changed files with 142961 additions and 75901 deletions

View File

@ -7,7 +7,7 @@
- [ ] Only relevant files were touched
- [ ] Only one feature/fix was added per PR and the code change compiles without warnings
- [ ] The code change is tested and works with Tasmota core ESP8266 V.2.7.4.9
- [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.11
- [ ] The code change is tested and works with Tasmota core ESP32 V.2.0.14
- [ ] I accept the [CLA](https://github.com/arendst/Tasmota/blob/development/CONTRIBUTING.md#contributor-license-agreement-cla).
_NOTE: The code change must pass CI tests. **Your PR cannot be merged unless tests pass**_

View File

@ -90,6 +90,9 @@ jobs:
- tasmota32s2cdc-safeboot
- tasmota32s3-safeboot
- tasmota32s3cdc-safeboot
- tasmota32c2-safeboot
- tasmota32c6-safeboot
- tasmota32c6cdc-safeboot
steps:
- uses: actions/checkout@v3
with:
@ -102,6 +105,7 @@ jobs:
run: |
pip install wheel
pip install -U platformio
cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini
- name: Run PlatformIO
run: platformio run -e ${{ matrix.variant }}
- name: Upload safeboot firmware artifacts

View File

@ -29,6 +29,9 @@ jobs:
- tasmota32s2cdc-safeboot
- tasmota32s3-safeboot
- tasmota32s3cdc-safeboot
- tasmota32c2-safeboot
- tasmota32c6-safeboot
- tasmota32c6cdc-safeboot
steps:
- uses: actions/checkout@v3
with:
@ -41,6 +44,7 @@ jobs:
run: |
pip install wheel
pip install -U platformio
cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini
- name: Run PlatformIO
run: platformio run -e ${{ matrix.variant }}
- name: Upload safeboot firmware artifacts

View File

@ -112,6 +112,9 @@ jobs:
- tasmota32s2cdc-safeboot
- tasmota32s3-safeboot
- tasmota32s3cdc-safeboot
- tasmota32c2-safeboot
- tasmota32c6-safeboot
- tasmota32c6cdc-safeboot
steps:
- uses: actions/checkout@v3
- name: Set up Python
@ -125,6 +128,7 @@ jobs:
pip install -U platformio
#platformio upgrade --dev
#platformio update
cp ./platformio_tasmota_core3_env_sample.ini ./platformio_tasmota_core3_env.ini
- name: Run PlatformIO
run: platformio run -e ${{ matrix.variant }}
- uses: actions/upload-artifact@v3

1
.gitignore vendored
View File

@ -27,6 +27,7 @@ tasmota/tasmota.ino.cpp
platformio_override.ini
platformio_tasmota_cenv.ini
platformio_tasmota_user_env.ini
platformio_tasmota_core3_env.ini
lib/libesp32/berry/generate/*
lib/libesp32/berry/berry

View File

@ -32,8 +32,8 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
| USE_SUNRISE | x | x / x | x | x | x | x |
| USE_RULES | x | x / x | x | x | x | x |
| USE_SCRIPT | - | - / - | - | - | - | - |
| USE_EXPRESSION | - | - / - | - | - | - | - |
| SUPPORT_IF_STATEMENT | - | - / - | - | - | - | - |
| USE_EXPRESSION | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB
| SUPPORT_IF_STATEMENT | - | - / x | - | - | - | - | Every ESP32 + ESP8266 > 1MB
| USE_HOTPLUG | - | - / - | - | - | - | - |
| USE_PROMETHEUS | - | - / - | - | - | - | - |
| USE_PING | - | - / - | - | - | - | - |
@ -132,6 +132,8 @@ Note: `minimal` variant is not listed as it shouldn't be used outside of the [up
| USE_MPR121 | - | - / - | - | - | - | - |
| USE_CCS811 | - | - / - | - | x | - | - |
| USE_CCS811_V2 | - | - / x | - | - | - | - |
| USE_ENS16x | - | - / - | - | - | - | - |
| USE_ENS210 | - | - / - | - | - | - | - |
| USE_MPU6050 | - | - / - | - | - | - | - |
| USE_DS3231 | - | - / - | - | - | - | - |
| USE_MGC3130 | - | - / - | - | - | - | - |

View File

@ -1,7 +1,92 @@
# Changelog
All notable changes to this project will be documented in this file.
## [Released] - Development
## [Released]
## [13.2.0] 20231018
- Release Quincy
## [13.1.0.4] 20231018
### Added
- Support for HC8 CO2 sensor (#19714)
- ESP32 commands ``Ds18Rescan`` and ``Ds18RetryRead`` (#19700)
### Breaking Changed
- Removed support for Homekit in favour of Matter (#19738)
### Changed
- ESP32 Framework (Arduino Core) from v2.0.13 to v2.0.14
- MAX31855/MAX6675 sensors driver support up to 6 (#19329)
- ESP32 analog from `analogRead()` to calibrated `analogReadMilliVolts()` (#19732)
- I2S refactoring in preparation for core 3 (#19749)
- Teleinfo use Apparent Power as Active Power approximation (#19756)
### Fixed
- ESP32 shutter frequency (#19717)
- ModbusBridge write memory leak (#19758)
### Removed
- WiFiClientSecure in favour of WiFiClientSecureLightBearSSL (#19725)
## [13.1.0.3] 20231003
### Added
- Support for Shelly PlusPMMini, Plus1Mini and Plus1PMMini
- Matter support for Virtual Devices controllable via Rules or Berry (#19520)
- Berry read and write Counters (#19558)
- ESP32 support for influxdb access using https (#19582)
- Support for ENS16x (air quality) and ENS210 (temp & RH) sensors (#19479)
- Support for non-persistent ``WebButton17`` to ``WebButton32`` (#19580)
- Command ``Mi32Name`` (#19619)
### Changed
- ESP32 Framework (Arduino Core) from v2.0.12 to v2.0.13
- ESP32 LVGL library from v8.3.9 to v8.3.10 (no functional change)
- Consolidate SGP40 and SGP41 into SGP4x driver (#19560)
- ESP32 Audio preparation for Arduino Core v3 (#19637)
- ESP32 LittleFS updated to version with grow option (#19635)
- ESP32 Partition Wizard grow filesystem support (#19645)
### Fixed
- ESP32 DS18x20 driver support extended over GPIO33
- ESP32 Shutter button quad press (#19589)
- Compile error with new email lib (#19608)
- ESP32 Arduino Core v2 wifi client flush (#19642)
## [13.1.0.2] 20230914
### Added
- Support for HDMI CEC protocol (#19434)
- Support different baudrates on BL0942
### Breaking Changed
- `Sendmail` upgraded to ESP-Mail-Client v3.4.9 from v1.2.0, using BearSSL instead of MbedTLS (#19460)
### Changed
- Berry fast_loop is now called every 5ms whatever the Sleep value (#19436)
- Reduce IRAM consumption of HDMI CEC to 1453 bytes (#19452)
- ESP32 Framework (Arduino Core) from v2.0.11 to v2.0.12
- ESP32 LVGL library from v8.3.8 to v8.3.9 (no functional change)
### Fixed
- PCF8574 mode 1 with base relays exception 3/28 regression from v12.4.0.4 (#19408)
- Berry make mdns compatible with non-IPv6 builds
- ESP32 Shutter migration (#19454)
- ESP32 Shutter multi press button events (#19465)
- Support for IPv6 link-local zones for esp-idf 5.1 (necessary for Matter)
- ESP32C3 relay click on restart
## [13.1.0.1] 20230831
### Added
- Commands to allow setting of timeprop parameters (#19310)
- Variables ``%power<1..28>%`` and ``%switch<1..28>%`` to rules (#19331)
- Experimental support for ESP32-C2 and ESP32-C6 using Arduino core v3.0
### Changed
- Display invert setting after tasmota start in uDisplay driver (#19337)
### Fixed
- Shutter invert (#19341, #19374)
- Teleinfo power (#19381)
- Exception 3 in IRHVAC (#19389)
## [13.1.0] 20230815
- Release Quentin

View File

@ -120,3 +120,6 @@ Index | Define | Driver | Device | Address(es) | Description
81 | USE_PCA9557 | xdrv_69 | PCA95xx | 0x18 - 0x1F | 8-bit I/O expander as virtual button/switch/relay
82 | USE_SGP4X | xsns_109 | SGP4X | 0x59 | Gas (TVOC/NOx index)
83 | USE_MAX17043 | xsns_110 | MAX17043 | 0x36 | Fuel-gauge for 3.7 Volt Lipo battery
84 | USE_ENS16x | xsns_111 | ENS16x | 0x52 - 0x53 | Gas (TVOC, eCO2) and air quality sensor
85 | USE_ENS210 | xsns_112 | ENS210 | 0x43 - 0x44 | Temperature and humidity sensor

View File

@ -36,9 +36,9 @@ While fallback or downgrading is common practice it was never supported due to S
This release will be supported from ESP8266/Arduino library Core version **2.7.4.9** due to reported security and stability issues on previous Core version. This will also support gzipped binaries.
This release will be supported from ESP32/Arduino library Core version **2.0.11**.
This release will be supported from ESP32/Arduino library Core version **2.0.14**.
Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.11 have been removed.
Support of ESP8266 Core versions before 2.7.4.9 and ESP32 Core versions before 2.0.14 have been removed.
## Support of TLS
@ -75,12 +75,12 @@ Latest released binaries can be downloaded from
- http://ota.tasmota.com/tasmota/release
Historical binaries can be downloaded from
- http://ota.tasmota.com/tasmota/release-13.1.0
- http://ota.tasmota.com/tasmota/release-13.2.0
The latter links can be used for OTA upgrades too like ``OtaUrl http://ota.tasmota.com/tasmota/release/tasmota.bin.gz``
### ESP32, ESP32-C3, ESP32-S2 and ESP32-S3 based
The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.11**.
The following binary downloads have been compiled with ESP32/Arduino library core version **2.0.14**.
- **tasmota32.bin** = The Tasmota version with most drivers including additional sensors and KNX for 4M+ flash. **RECOMMENDED RELEASE BINARY**
- **tasmota32xy.bin** = The Tasmota version with most drivers including additional sensors and KNX for ESP32-C3/S2/S3 and 4M+ flash.
@ -100,7 +100,7 @@ Latest released binaries can be downloaded from
- https://ota.tasmota.com/tasmota32/release
Historical binaries can be downloaded from
- https://ota.tasmota.com/tasmota32/release-13.1.0
- https://ota.tasmota.com/tasmota32/release-13.2.0
The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasmota.com/tasmota32/release/tasmota32.bin``
@ -110,66 +110,54 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm
[Complete list](BUILDS.md) of available feature and sensors.
## Changelog v13.1.0 Quentin
## Changelog v13.2.0 Quincy
### Added
- Command ``BrRestart`` to restart the Berry VM (experimental) [#19003](https://github.com/arendst/Tasmota/issues/19003)
- Command ``Delay -1`` to wait until next second [#18984](https://github.com/arendst/Tasmota/issues/18984)
- Command ``Restart 9`` to save all changes and go into deepsleep waiting for a reset [#19024](https://github.com/arendst/Tasmota/issues/19024)
- Support for MAX17043 fuel-gauge systems Lipo batteries [#18788](https://github.com/arendst/Tasmota/issues/18788)
- Support for multiple PCA9685 with extended functionality [#18805](https://github.com/arendst/Tasmota/issues/18805)
- Support for SGP41 TVOC/NOx Sensor [#18880](https://github.com/arendst/Tasmota/issues/18880)
- Support for DeepSleep battery level percentage [#19134](https://github.com/arendst/Tasmota/issues/19134)
- Zigbee decode Aqara 0000/FF01 attribute 03 as Temperature [#19210](https://github.com/arendst/Tasmota/issues/19210)
- ESP32 prepare for Arduino Core v3 and esp-idf v5 [#19264](https://github.com/arendst/Tasmota/issues/19264)
- Berry `getgbl` performance counter to `debug.counters()` [#19070](https://github.com/arendst/Tasmota/issues/19070)
- Berry `_class` can be used in `static var` initialization code [#19088](https://github.com/arendst/Tasmota/issues/19088)
- Berry `energy.update_total()` to call `EnergyUpdateTotal()` from energy driver [#19117](https://github.com/arendst/Tasmota/issues/19117)
- Berry `tasmota.loglevel()` and `tasmota.rtc_utc()` for faster performance [#19152](https://github.com/arendst/Tasmota/issues/19152)
- Berry metrics for memory allocation/deallocation/reallocation [#19150](https://github.com/arendst/Tasmota/issues/19150)
- Berry AES CCM decrypting in a single call to avoid any object allocation [#19153](https://github.com/arendst/Tasmota/issues/19153)
- Berry bytes `get` and `set` work for 3 bytes values [#19225](https://github.com/arendst/Tasmota/issues/19225)
- Partition Wizard is now able to convert to safeboot from Shelly partition layout [#19034](https://github.com/arendst/Tasmota/issues/19034)
- Matter option to disable bridge mode [#18992](https://github.com/arendst/Tasmota/issues/18992)
- Matter mini-profiler [#19075](https://github.com/arendst/Tasmota/issues/19075)
- Matter support for fabric_filtered request (for Google compatibility) [#19249](https://github.com/arendst/Tasmota/issues/19249)
- Experimental support for ESP32-C2 and ESP32-C6 using Arduino core v3
- Commands to allow setting of timeprop parameters [#19310](https://github.com/arendst/Tasmota/issues/19310)
- Command ``Mi32Name`` [#19619](https://github.com/arendst/Tasmota/issues/19619)
- Variables ``%power<1..28>%`` and ``%switch<1..28>%`` to rules [#19331](https://github.com/arendst/Tasmota/issues/19331)
- Support different baudrates on BL0942
- Support for Shelly PlusPMMini, Plus1Mini and Plus1PMMini
- Support for HDMI CEC protocol [#19434](https://github.com/arendst/Tasmota/issues/19434)
- Support for ENS16x (air quality) and ENS210 (temp & RH) sensors [#19479](https://github.com/arendst/Tasmota/issues/19479)
- Support for HC8 CO2 sensor [#19714](https://github.com/arendst/Tasmota/issues/19714)
- Support for non-persistent ``WebButton17`` to ``WebButton32`` [#19580](https://github.com/arendst/Tasmota/issues/19580)
- ESP32 commands ``Ds18Rescan`` and ``Ds18RetryRead`` [#19700](https://github.com/arendst/Tasmota/issues/19700)
- ESP32 support for influxdb access using https [#19582](https://github.com/arendst/Tasmota/issues/19582)
- Berry read and write Counters [#19558](https://github.com/arendst/Tasmota/issues/19558)
- Matter support for Virtual Devices controllable via Rules or Berry [#19520](https://github.com/arendst/Tasmota/issues/19520)
### Breaking Changed
- Berry `bool( [] )` and `bool( {} )` now evaluate as `false` [#18986](https://github.com/arendst/Tasmota/issues/18986)
- Berry `import strict` now detects useless expression without side effects [#18997](https://github.com/arendst/Tasmota/issues/18997)
- `Sendmail` upgraded to ESP-Mail-Client v3.4.9 from v1.2.0, using BearSSL instead of MbedTLS [#19460](https://github.com/arendst/Tasmota/issues/19460)
- Removed support for Homekit in favour of Matter [#19738](https://github.com/arendst/Tasmota/issues/19738)
### Changed
- IRremoteESP8266 library from v2.8.5 to v2.8.6
- ESP32 Framework (Arduino Core) from v2.0.10 to v2.0.11
- ESP32 LVGL library from v8.3.7 to v8.3.8 (no functional change)
- Initial ``DisplayMode`` from 1 to 0 and ``DisplayDimmmer`` from 10% to 50% [#19138](https://github.com/arendst/Tasmota/issues/19138)
- Configuration backup and restore now supports ``.xdrvsetXXX`` files too [#18295](https://github.com/arendst/Tasmota/issues/18295)
- Reduced log level for TeleInfo [#19216](https://github.com/arendst/Tasmota/issues/19216)
- Console height from default 318 pixels to viewport [#19241](https://github.com/arendst/Tasmota/issues/19241)
- Shutter button hold behaviour with grouptopic [#19263](https://github.com/arendst/Tasmota/issues/19263)
- Thermostat improvements [#19279](https://github.com/arendst/Tasmota/issues/19279)
- PID controller improvements [#19285](https://github.com/arendst/Tasmota/issues/19285)
- HDC1080 detect device offline [#19298](https://github.com/arendst/Tasmota/issues/19298)
- ADE7953 lowered no load threshold [#19302](https://github.com/arendst/Tasmota/issues/19302)
- ESP32 shutter driver support up to 16 shutters [#18295](https://github.com/arendst/Tasmota/issues/18295)
- ESP32 autodetect flashsize and adjust filesystem [#19215](https://github.com/arendst/Tasmota/issues/19215)
- Berry extend `range(lower, upper, incr)` to arbitrary increment [#19120](https://github.com/arendst/Tasmota/issues/19120)
- Berry updated syntax highlighting plugin for VSCode [#19123](https://github.com/arendst/Tasmota/issues/19123)
- Berry `mqtt.publish` now distinguishes between `string` and `bytes` [#19196](https://github.com/arendst/Tasmota/issues/19196)
- Matter support for temperature in Fahrenheit (`SetOption8 1`) [#18987](https://github.com/arendst/Tasmota/issues/18987)
- Matter improve responsiveness [#19002](https://github.com/arendst/Tasmota/issues/19002)
- Matter improve latency for remote commands [#19072](https://github.com/arendst/Tasmota/issues/19072)
- Matter improve latency for single attribute reads and single commands [#19158](https://github.com/arendst/Tasmota/issues/19158)
- Matter increased polling frequency for local switches/occupancy [#19242](https://github.com/arendst/Tasmota/issues/19242)
- ESP32 Framework (Arduino Core) from v2.0.11 to v2.0.14
- ESP32 LVGL library from v8.3.8 to v8.3.10 (no functional change)
- Display invert setting after tasmota start in uDisplay driver [#19337](https://github.com/arendst/Tasmota/issues/19337)
- Consolidate SGP40 and SGP41 into SGP4x driver [#19560](https://github.com/arendst/Tasmota/issues/19560)
- MAX31855/MAX6675 sensors driver support up to 6 [#19329](https://github.com/arendst/Tasmota/issues/19329)
- Teleinfo use Apparent Power as Active Power approximation [#19756](https://github.com/arendst/Tasmota/issues/19756)
- ESP32 LittleFS updated to version with grow option [#19635](https://github.com/arendst/Tasmota/issues/19635)
- ESP32 I2S audio preparation for Arduino Core v3 [#19637](https://github.com/arendst/Tasmota/issues/19637)
- ESP32 analog from `analogRead()` to calibrated `analogReadMilliVolts()` [#19732](https://github.com/arendst/Tasmota/issues/19732)
### Fixed
- Berry Walrus Operator [#18982](https://github.com/arendst/Tasmota/issues/18982)
- MiElHVAC power commands regression from v12.4.0.1 [#18923](https://github.com/arendst/Tasmota/issues/18923)
- Zero cross dimmer minimum interrupt time [#19211](https://github.com/arendst/Tasmota/issues/19211)
- Fade would fail when the difference between start and target would be too small [#19248](https://github.com/arendst/Tasmota/issues/19248)
- Inverted shutter [#19243](https://github.com/arendst/Tasmota/issues/19243)
- ESP8266 SPI initialization for scripter, filesystem and MFRC522 [#19209](https://github.com/arendst/Tasmota/issues/19209)
- Matter support for large atribute responses [#19252](https://github.com/arendst/Tasmota/issues/19252)
- Matter auto-configuration Relay indices [#19255](https://github.com/arendst/Tasmota/issues/19255)
- Shutter invert [#19341](https://github.com/arendst/Tasmota/issues/19341) and [#19374](https://github.com/arendst/Tasmota/issues/19374)
- Teleinfo power [#19381](https://github.com/arendst/Tasmota/issues/19381)
- Exception 3 in IRHVAC [#19389](https://github.com/arendst/Tasmota/issues/19389)
- PCF8574 mode 1 with base relays exception 3/28 regression from v12.4.0.4 [#19408](https://github.com/arendst/Tasmota/issues/19408)
- ModbusBridge write memory leak [#19758](https://github.com/arendst/Tasmota/issues/19758)
- ESP32 DS18x20 driver support extended over GPIO33
- ESP32 Support for IPv6 link-local zones for esp-idf 5.1 (necessary for Matter)
- ESP32 Shutter migration [#19454](https://github.com/arendst/Tasmota/issues/19454)
- ESP32 Shutter multi press button events [#19465](https://github.com/arendst/Tasmota/issues/19465)
- ESP32 Shutter button quad press [#19589](https://github.com/arendst/Tasmota/issues/19589)
- ESP32 shutter frequency [#19717](https://github.com/arendst/Tasmota/issues/19717)
- ESP32 Arduino Core v2 wifi client flush [#19642](https://github.com/arendst/Tasmota/issues/19642)
- ESP32 Partition Wizard grow filesystem support [#19645](https://github.com/arendst/Tasmota/issues/19645)
- ESP32C3 relay click on restart
- Matter support for Virtual Devices controllable via Rules or Berry [#19520](https://github.com/arendst/Tasmota/issues/19520)
### Removed
- Support for ESP32-C3 with chip revision below 3 (old development boards)
- Removed support for Homekit in favour of Matter [#19738](https://github.com/arendst/Tasmota/issues/19738)

View File

@ -5,7 +5,7 @@
# Templates
Find below the available templates as of August 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
Find below the available templates as of October 2023. More template information can be found in the [Tasmota Device Templates Repository](http://blakadder.github.io/templates)
## Adapter Board
```
@ -258,6 +258,7 @@ Zemismart Backlit {"NAME":"WF-CS01","GPIO":[544,227,289,34,226,161,0,
## DIN Relay
```
CBI Astute Smart Controller {"NAME":"CBI Astute","GPIO":[2624,320,0,0,0,224,0,0,2720,32,2656,0,0,0],"FLAG":0,"BASE":6}
CurrySmarter Power Monitoring 30A {"NAME":"30A Breaker on Led","GPIO":[0,0,0,0,7584,224,0,0,2720,32,2656,2624,320,0],"FLAG":0,"BASE":18}
EARU DIN Circuit Breaker 1P 32A/50A {"NAME":"RDCBC-1P","GPIO":[320,0,0,0,0,0,0,0,32,224,0,0,0,0],"FLAG":0,"BASE":18}
Hoch Circuit Breaker 1P {"NAME":"HOCH ZJSB9","GPIO":[32,0,0,0,0,0,0,0,224,320,0,0,0,0],"FLAG":0,"BASE":18}
@ -297,7 +298,7 @@ Adafruit QT Py ESP32 Pico {"NAME":"QTPy ESP32 Pico","GPIO":[32,3200,0,3232,1,
AZ-Envy Environmental Sensor {"NAME":"AZ Envy","GPIO":[32,0,320,0,640,608,0,0,0,0,0,0,0,4704],"FLAG":0,"BASE":18}
Coiaca Tasmota {"NAME":"AWR01t","GPIO":[576,1,1,128,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":18}
Coiaca Tasmota Development Board AWR12 {"NAME":"AWR12t","GPIO":[320,1,1,1,1,1,0,0,1,1,1,1,1,1],"FLAG":0,"BASE":18}
Dasduino CONNECTPLUS {"NAME":"Dasduino CONNECT","GPIO":[1,1,1376,1,640,608,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18}
Dasduino CONNECT {"NAME":"Dasduino CONNECT","GPIO":[1,1,1376,1,640,608,1,1,1,1,1,1,1,1],"FLAG":0,"BASE":18}
Dasduino CONNECTPLUS {"NAME":"Dasduino CONNECTPLUS","GPIO":[32,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,640,608,1,0,1,1,1,0,0,0,0,1376,1,1,1,1,0,0,1],"FLAG":0,"BASE":1}
Espoir Rev 1.0.0 PoE+ {"NAME":"Espoir","GPIO":[0,0,1,0,1,1,1,1,1,1,1,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0,0,0,5568,5600,1,7968,1,1,1,1],"FLAG":0,"BASE":1}
KinCony 128 Channel Controller {"NAME":"KC868-A128","GPIO":[0,1,0,1,609,640,1,1,1,3232,3200,641,608,1,5600,0,0,1,0,5568,0,1,0,0,0,0,0,0,0,0,4705,4707,4706,0,0,4704],"FLAG":0,"BASE":1}
@ -704,6 +705,7 @@ QS-WIFI-RGBCW {"NAME":"QS-WIFI-RGBCW","GPIO":[0,0,32,0,544,417,0,
RGB 12-24V {"NAME":"WS03","GPIO":[0,0,0,0,0,0,0,0,418,417,416,0,0,0],"FLAG":0,"BASE":18}
RGB+CCT 12-24V {"NAME":"WS05","GPIO":[0,0,0,0,0,420,0,0,418,417,416,419,0,0],"FLAG":0,"BASE":18}
RGBW 12-24V {"NAME":"*WS04","GPIO":[0,0,0,0,0,0,0,0,417,418,416,419,0,0],"FLAG":0,"BASE":18}
Robus CCT {"NAME":"RobusCCT","GPIO":[0,0,0,0,32,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
Shelly RGBW2 {"NAME":"Shelly RGBW2","GPIO":[0,0,288,0,419,1,0,0,416,32,418,417,0,0],"FLAG":0,"BASE":18}
Spectrum Smart RGBCCT {"NAME":"Spectrum Smart RGB CCT Controller","GPIO":[32,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Tuya RGBCCT {"NAME":"AP-5CH-1","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
@ -714,7 +716,7 @@ ZJ-WF-ESP-A v1.1 {"NAME":"RGB2","GPIO":[0,0,0,0,0,0,0,0,417,416,418,
## LED Strip
```
Aldi Casalux RGB {"NAME":"DW-RGB-WI01","GPIO":[1088,0,0,0,416,0,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
ARLEC 5m Colour Changing "Not available"
ARLEC 5m Colour Changing {"NAME":"ALD557HA","GPIO":[0,0,0,1376,0,0,0,0,0,1088,0,0,0,0],"FLAG":0,"BASE":18}
Arlec Smart 1m CCT LED Strip Light {"NAME":"ALD155HA","GPIO":[0,0,1088,0,0,416,0,0,0,417,0,0,0,0],"FLAG":0,"BASE":18}
Arlec Smart 2m LED Colour Changing Strip Light {"NAME":"Arlec_Light_Strip","GPIO":[1,1,1088,1,416,419,1,1,417,420,418,0,1,1],"FLAG":0,"BASE":18}
Arlec Smart 5m White & Colour Changing {"NAME":"ALD556HA","GPIO":[0,0,1088,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
@ -913,6 +915,7 @@ Albohes PS-1602 {"NAME":"Albohes PC1606","GPIO":[32,0,0,0,0,225,33,
Amzdest Dual {"NAME":"Amzdest c158","GPIO":[0,32,0,225,2720,2656,0,0,224,2624,0,0,0,0],"FLAG":0,"BASE":18}
Amzdest IP55 {"NAME":"C168 Outdoor","GPIO":[0,0,0,2624,2720,2656,0,0,224,320,225,226,32,0],"FLAG":0,"BASE":18}
Aoycocr X13 {"NAME":"Aoycocr X13","GPIO":[0,0,320,0,0,0,0,0,225,32,0,224,0,0],"FLAG":0,"BASE":18}
Arlec IP44 Weatherproof {"NAME":"PC44HA","GPIO":[0,0,0,35,2720,2656,0,0,2592,320,224,0,0,0],"FLAG":0,"BASE":18}
Atomi {"NAME":"AtomiSmartPlug","GPIO":[0,0,0,0,320,576,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Blitzwolf 16A IP44 Dual {"NAME":"Blitzwolf BW-SHP14","GPIO":[0,320,0,32,0,321,0,0,224,0,225,0,0,0],"FLAG":0,"BASE":18}
BN-Link {"NAME":"BNC-60/U130T","GPIO":[1,0,1,0,1,320,1,1,224,32,1,0,0,1],"FLAG":0,"BASE":18}
@ -1054,6 +1057,7 @@ Athom 16A UK {"NAME":"Athom PG04-UK16A","GPIO":[0,0,0,32,2720,26
Athom 16A UK V2 {"NAME":"Athom Plug V2","GPIO":[0,0,0,3104,0,32,0,0,224,576,0,0,0,0],"FLAG":0,"BASE":18}
Athom 16A US {"NAME":"Athom PG03-US16A","GPIO":[0,0,0,32,2720,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18}
Athom 16A US V2 {"NAME":"Athom Plug V2","GPIO":[0,0,0,3104,0,32,0,0,224,576,0,0,0,0],"FLAG":0,"BASE":18}
Athom Plug V3 {"NAME":"Athom Plug V3","GPIO":[0,0,0,32,0,224,576,0,0,0,0,0,0,0,0,0,0,0,0,0,3104,0],"FLAG":0,"BASE":1}
Atlantis {"NAME":"Atlantis Smart Plug","GPIO":[32,0,0,0,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18}
Atomi AT1217 {"NAME":"AT1217","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Aubess 16A {"NAME":"Aubess 16A Power Monitoring Plug","GPIO":[0,32,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18}
@ -1267,6 +1271,7 @@ HiHome {"NAME":"HIhome WPP-10S","GPIO":[320,0,576,1,0,2720
HiHome {"NAME":"HiHome WPP-16T","GPIO":[32,320,1,1,2720,2656,0,0,33,1,225,2592,224,4704],"FLAG":0,"BASE":18}
HIPER IoT P01 {"NAME":"HIPER IoT P01","GPIO":[0,0,0,0,0,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
HIPER IoT P05 {"NAME":"HIPER IoT P05","GPIO":[0,320,0,32,0,0,0,0,0,224,0,0,0,0],"FLAG":0,"BASE":18}
HIPER IoT P09 {"NAME":"HIPER IoT P09","GPIO":[32,0,0,0,0,320,0,0,224,0,0,0,0,0],"FLAG":0,"BASE":18}
hiwild W-US002 {"NAME":"W-US002","GPIO":[0,32,0,0,0,0,0,0,0,288,224,0,576,0],"FLAG":0,"BASE":18}
HLT-309 {"NAME":"HLT-309","GPIO":[0,0,0,0,0,0,0,0,0,32,0,224,0,0],"FLAG":0,"BASE":18}
Hoin 10A {"NAME":"NIOH XS-SSC01","GPIO":[0,32,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":18}
@ -1378,6 +1383,7 @@ Maxcio YX-DE04 {"NAME":"Maxcio YX-DE04","GPIO":[1,32,1,224,320,419
MaxKare XKJJ-0218 {"NAME":"MaxKare XKJJ-0","GPIO":[0,0,0,0,33,2688,0,0,224,32,2656,225,2592,0],"FLAG":0,"BASE":18}
Maxus Brio Head 16A {"NAME":"Brio-W-Head16","GPIO":[0,0,320,0,0,2720,0,0,2624,32,2656,224,0,0],"FLAG":0,"BASE":18}
Medion Life+ S85225 {"NAME":"Medion","GPIO":[0,0,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":52}
MELINK Smart Socket {"NAME":"MeLink ML1SSO20","GPIO":[0,32,0,32,2720,2656,0,0,2624,288,224,0,0,0],"FLAG":0,"BASE":18}
Merkury Innovations 4 Outlets {"NAME":"MI-WW119-199W","GPIO":[320,3200,0,3232,225,32,0,0,224,226,227,0,0,0],"FLAG":0,"BASE":18}
Merkury MI-WW101-199 {"NAME":"merkury WW101","GPIO":[0,0,0,0,0,0,0,0,320,64,0,224,0,0],"FLAG":0,"BASE":18}
Merkury MI-WW102-199L {"NAME":"MIC-WW102","GPIO":[32,0,0,0,0,0,0,0,0,320,224,0,0,0],"FLAG":0,"BASE":36}
@ -1403,6 +1409,7 @@ MXQ LED Nightlight {"NAME":"MXQ SP06","GPIO":[0,0,0,0,288,192,0,0,225,
Nanxin NX-SM400 {"NAME":"NX-SM400","GPIO":[0,0,0,32,2720,2656,0,0,2592,288,224,0,0,0],"FLAG":0,"BASE":18}
Naxa NSH-1000 {"NAME":"Naxa NSH-1000","GPIO":[0,0,0,0,32,0,0,0,321,320,224,0,0,0],"FLAG":0,"BASE":18}
Nedis P110 {"NAME":"Nedis WIFIP110","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
Nedis P120 {"NAME":"WIFIP120EWT","GPIO":[32,0,0,0,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
Nedis P130 {"NAME":"WIFIP130FWT","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
Nedis Schuko Type F 16A {"NAME":"WIFIP120FWT","GPIO":[32,0,0,0,2688,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
NEO Coolcam 10A {"NAME":"Neo Coolcam 10","GPIO":[32,0,0,0,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":49}
@ -1572,10 +1579,12 @@ TP28Y {"NAME":"TP28Y","GPIO":[0,0,0,32,2720,2656,0,0,2624
Treatlife Dimmable {"NAME":"DP20","GPIO":[0,2272,0,2304,0,0,0,0,0,0,0,0,0,0],"FLAG":0,"BASE":54,"CMND":"TuyaMCU 21,2 | SO20 1 | SO54 1"}
Treatlife Smart {"NAME":"Treatlife SK50","GPIO":[1,1,1,1,320,576,1,1,224,1,32,1,1,1],"FLAG":0,"BASE":18}
Tuya 16A Nightlight {"NAME":"Nightlight","GPIO":[225,0,320,0,226,227,0,0,34,64,0,224,0,0],"FLAG":0,"BASE":18}
Tuya 20A {"NAME":"Tuya 20A Power Monitoring Plug","GPIO":[1,1,1,32,2720,224,1,1,1,320,289,1,1,1],"FLAG":0,"BASE":18}
U10 Series {"NAME":"WIFI-Socket","GPIO":[1,32,1,1,1,1,1,1,1,320,224,1,1,4704],"FLAG":0,"BASE":18}
Ucomen Night Light {"NAME":"UCOMEN Plug","GPIO":[0,0,0,0,544,320,0,0,224,32,0,0,0,0],"FLAG":0,"BASE":18}
UltraBrite {"NAME":"UltraBrite Smart Plug","GPIO":[1,1,1,1,288,289,1,1,224,32,1,1,1,1],"FLAG":0,"BASE":18}
Ultralink UL-P01W {"NAME":"UL-P01W","GPIO":[0,288,0,32,2720,2656,0,0,2624,544,224,0,0,0],"FLAG":0,"BASE":18}
Umax U-Smart Duo {"NAME":"Umax Duo Plug","GPIO":[33,0,0,0,2688,2656,0,0,2624,544,224,225,32,0],"FLAG":0,"BASE":18}
Unlocked Automation 15A {"NAME":"UA 100","GPIO":[0,0,0,0,320,321,0,0,224,32,0,0,0,1],"FLAG":0,"BASE":18}
UP111 {"NAME":"UP111","GPIO":[0,576,0,32,2720,2656,0,0,2624,320,224,0,0,0],"FLAG":0,"BASE":18}
Upstone {"NAME":"UPSTONE","GPIO":[1,1,544,1,320,1,0,0,224,32,1,1,1,1],"FLAG":0,"BASE":18}
@ -2165,7 +2174,7 @@ Shelly Duo RGBW 9W 800lm {"NAME":"Shelly Duo RGBW","GPIO":[0,0,0,0,0,419,0,0
Smart 810lm {"NAME":"OOOLED 60W RGB","GPIO":[0,0,0,0,418,419,0,0,416,0,417,0,0,4704],"FLAG":0,"BASE":18}
SmartLED 9W 400lm {"NAME":"SmartLED RGBWW","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Smartyfi 600lm {"NAME":"SMARTYFI 9W","GPIO":[0,0,0,0,416,419,0,0,417,0,418,0,0,0],"FLAG":0,"BASE":18}
Smitch 7W {"NAME":"Smitch RGB 7W SB-1602","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
Smitch 7W {"NAME":"Smitch RGB 7W SB-1602","GPIO":[0,0,0,0,2912,419,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18}
Solimo 12W {"NAME":"Solimo RGBCCT 12","GPIO":[0,0,0,0,416,420,0,0,417,419,418,0,0,0],"FLAG":0,"BASE":18}
Solimo 810lm {"NAME":"Solimo RGBWW 9","GPIO":[0,0,0,0,416,419,0,0,417,420,418,0,0,0],"FLAG":0,"BASE":18}
SPC Sirius 380 {"NAME":"SPC Sirius 380","GPIO":[0,0,0,0,2912,416,0,0,417,2976,2944,0,0,0],"FLAG":0,"BASE":18}

44
boards/esp32c2.json Normal file
View File

@ -0,0 +1,44 @@
{
"build": {
"arduino":{
"ldscript": "esp32c2_out.ld"
},
"core": "esp32",
"extra_flags": "-DESP32_4M -DESP32C2",
"f_cpu": "120000000L",
"f_flash": "60000000L",
"flash_mode": "dio",
"mcu": "esp32c2",
"variant": "esp32c2",
"partitions": "partitions/esp32_partition_app2880k_fs320k.csv"
},
"connectivity": [
"wifi",
"bluetooth"
],
"debug": {
"openocd_target": "esp32c2.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Espressif Generic ESP32-C2 = 4M Flash",
"upload": {
"arduino": {
"flash_extra_images": [
[
"0x10000",
"variants/tasmota/tasmota32c2-safeboot.bin"
]
]
},
"flash_size": "4MB",
"maximum_ram_size": 278528,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
"vendor": "Espressif"
}

44
boards/esp32c2_2M.json Normal file
View File

@ -0,0 +1,44 @@
{
"build": {
"arduino":{
"ldscript": "esp32c2_out.ld"
},
"core": "esp32",
"extra_flags": "-DESP32_2M -DESP32C2",
"f_cpu": "120000000L",
"f_flash": "60000000L",
"flash_mode": "dio",
"mcu": "esp32c2",
"variant": "esp32c2",
"partitions": "partitions/esp32_partition_app1245k_fs64k.csv"
},
"connectivity": [
"wifi",
"bluetooth"
],
"debug": {
"openocd_target": "esp32c2.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Espressif Generic ESP32-C2 = 2M Flash, Tasmota 1245kB Code/OTA, 64k FS",
"upload": {
"arduino": {
"flash_extra_images": [
[
"0x10000",
"variants/tasmota/tasmota32c2-safeboot.bin"
]
]
},
"flash_size": "2MB",
"maximum_ram_size": 278528,
"maximum_size": 2097152,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
"vendor": "Espressif"
}

View File

@ -7,7 +7,7 @@
"extra_flags": "-DESP32_4M -DESP32C6",
"f_cpu": "160000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"flash_mode": "qio",
"mcu": "esp32c6",
"variant": "esp32c6",
"partitions": "partitions/esp32_partition_app2880k_fs320k.csv"

45
boards/esp32c6cdc.json Normal file
View File

@ -0,0 +1,45 @@
{
"build": {
"arduino":{
"ldscript": "esp32c6_out.ld"
},
"core": "esp32",
"extra_flags": "-DARDUINO_USB_MODE=1 -DESP32_4M -DESP32C6 -DUSE_USB_CDC_CONSOLE",
"f_cpu": "160000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"mcu": "esp32c6",
"variant": "esp32c6",
"partitions": "partitions/esp32_partition_app2880k_fs320k.csv"
},
"connectivity": [
"wifi",
"bluetooth"
],
"debug": {
"openocd_target": "esp32c6.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Espressif Generic ESP32-C6 >= 4M Flash, Tasmota 2880k Code/OTA, 320k FS",
"upload": {
"arduino": {
"flash_extra_images": [
[
"0x10000",
"variants/tasmota/tasmota32c6cdc-safeboot.bin"
]
]
},
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"before_reset": "usb_reset",
"speed": 460800
},
"url": "https://docs.espressif.com/projects/espressif-esp-dev-kits/en/latest/esp32c6/esp32-c6-devkitc-1/index.html",
"vendor": "Espressif"
}

View File

@ -68,10 +68,28 @@
#define SPI_HOST SPI1_HOST
#define HSPI_HOST SPI2_HOST
#define VSPI_HOST SPI2_HOST /* No SPI3_host on C3 */
#if ESP_IDF_VERSION_MAJOR < 5
// fix a bug in esp-idf 4.4 for esp32c3
#ifndef REG_SPI_BASE
#define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
// SPI_MOSI_DLEN_REG is not defined anymore in esp32c3, instead use SPI_MS_DLEN_REG
#define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x)
#endif // REG_SPI_BASE
#endif //ESP_IDF_VERSION_MAJOR < 5
#elif CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
#define SPI_HOST SPI1_HOST
#define HSPI_HOST SPI1_HOST /* No SPI2_host on C2/C6 */
#define VSPI_HOST SPI1_HOST /* No SPI3_host on C2/C6 */
#define VSPI SPI
// #if ESP_IDF_VERSION_MAJOR < 5
// // fix a bug in esp-idf 4.4 for esp32c3
// #ifndef REG_SPI_BASE
// #define REG_SPI_BASE(i) (DR_REG_SPI1_BASE + (((i)>1) ? (((i)* 0x1000) + 0x20000) : (((~(i)) & 1)* 0x1000 )))
// // SPI_MOSI_DLEN_REG is not defined anymore in esp32c3, instead use SPI_MS_DLEN_REG
#define SPI_MOSI_DLEN_REG(x) SPI_MS_DLEN_REG(x)
// #endif // REG_SPI_BASE
// #endif //ESP_IDF_VERSION_MAJOR < 5
#endif // TARGET

View File

@ -53,7 +53,7 @@
*/
#include "Arduino.h"
#include <EEPROM.h>
//#include <EEPROM.h>
#include <ESP8266WiFi.h>
#include <WiFiUdp.h>
#include <ESP8266WebServer.h>

View File

@ -19,5 +19,9 @@
"frameworks": "Arduino",
"examples": [
"examples/*/*.ino"
]
],
"build": {
"includeDir": ".",
"flags": [ "-Wno-stringop-overread" ]
}
}

View File

@ -19,6 +19,7 @@
*/
#include <Arduino.h>
#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S
#ifdef ESP32
#include "driver/i2s.h"
#elif defined(ARDUINO_ARCH_RP2040) || ARDUINO_ESP8266_MAJOR >= 3
@ -374,3 +375,4 @@ bool AudioOutputI2S::stop()
i2sOn = false;
return true;
}
#endif // TODO Arduino 3.0 Port I2S

View File

@ -19,6 +19,7 @@
*/
#include <Arduino.h>
#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S
#ifdef ESP32
#include "driver/i2s.h"
#elif defined(ARDUINO_ARCH_RP2040) || ARDUINO_ESP8266_MAJOR >= 3
@ -119,3 +120,4 @@ bool AudioOutputI2SNoDAC::ConsumeSample(int16_t sample[2])
#endif
return true;
}
#endif // ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S

View File

@ -37,9 +37,11 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#if defined(ESP32) || defined(ESP8266)
#include <Arduino.h>
#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S
#if defined(ESP32)
#include "driver/i2s.h"
#include "soc/rtc.h"
@ -293,3 +295,4 @@ bool AudioOutputSPDIF::stop()
}
#endif
#endif // ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S

View File

@ -18,6 +18,9 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <Arduino.h>
#if ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S
#if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2
#include "AudioOutputULP.h"
@ -260,3 +263,4 @@ bool AudioOutputULP::stop()
}
#endif
#endif // ESP_IDF_VERSION_MAJOR < 5 // TODO Arduino 3.0 Port I2S

View File

@ -2783,7 +2783,7 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_
if(rice_parameter < pesc) {
partitioned_rice_contents->raw_bits[partition] = 0;
u = (partition_order == 0 || partition > 0)? partition_samples : partition_samples - predictor_order;
if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter))
if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, (int*) residual + sample, u, rice_parameter))
return false; /* read_callback_ sets the state for us */
sample += u;
}
@ -2792,7 +2792,7 @@ FLAC__bool read_residual_partitioned_rice_(FLAC__StreamDecoder *decoder, uint32_
return false; /* read_callback_ sets the state for us */
partitioned_rice_contents->raw_bits[partition] = rice_parameter;
for(u = (partition_order == 0 || partition > 0)? 0 : predictor_order; u < partition_samples; u++, sample++) {
if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, (long int*) &i, rice_parameter))
return false; /* read_callback_ sets the state for us */
residual[sample] = i;
}

View File

@ -1636,7 +1636,7 @@ void III_imdct_l(mad_fixed_t const [18], mad_fixed_t [36], unsigned int);
# else
# if 1
static
void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[18])
void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[17])
{
mad_fixed_t a0, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12;
mad_fixed_t a13, a14, a15, a16, a17, a18, a19, a20, a21, a22, a23, a24, a25;

View File

@ -0,0 +1,27 @@
# below are the high-level patches made to the standard ESP8266audio libraries
# For Arduino 3 (gcc has a higher level of checks
libmad/layer3.c replace (line 1639)
void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[18])
to
void fastsdct(mad_fixed_t const x[9], mad_fixed_t y[17])
libflac/stream_decoder.c
line 2786
if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, residual + sample, u, rice_parameter))
to
if(!FLAC__bitreader_read_rice_signed_block(decoder->private_->input, (int*) residual + sample, u, rice_parameter))
line 2795
if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, &i, rice_parameter))
to
if(!FLAC__bitreader_read_raw_int32(decoder->private_->input, (long int*) &i, rice_parameter))
l3loop.cpp
remove all 'register'
mult_noarch_gcc.h
remove all 'register'

View File

@ -13,6 +13,11 @@ extern "C" {
}
#endif // ESP8266
#include <Arduino.h>
#if defined(ESP32)
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
#include <driver/gpio.h>
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#endif
#endif // UNIT_TEST
#include <algorithm>
#ifdef UNIT_TEST
@ -242,8 +247,13 @@ static void USE_IRAM_ATTR gpio_intr() {
// @see https://github.com/espressif/arduino-esp32/blob/6b0114366baf986c155e8173ab7c22bc0c5fcedc/cores/esp32/esp32-hal-timer.c#L176-L178
timer->dev->config.alarm_en = 1;
#else // _ESP32_IRRECV_TIMER_HACK
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0);
timerAttachInterrupt(timer, &read_timeout);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timerWrite(timer, 0);
timerAlarmEnable(timer);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#endif // _ESP32_IRRECV_TIMER_HACK
#endif // ESP32
}
@ -359,7 +369,11 @@ void IRrecv::enableIRIn(const bool pullup) {
#if defined(ESP32)
// Initialise the ESP32 timer.
// 80MHz / 80 = 1 uSec granularity.
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timer = timerBegin(80);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timer = timerBegin(_timer_num, 80, true);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#ifdef DEBUG
if (timer == NULL) {
DPRINT("FATAL: Unable enable system timer: ");
@ -367,12 +381,17 @@ void IRrecv::enableIRIn(const bool pullup) {
}
#endif // DEBUG
assert(timer != NULL); // Check we actually got the timer.
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerAlarm(timer, MS_TO_USEC(params.timeout), ONCE, 0);
timerAttachInterrupt(timer, &read_timeout);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
// Set the timer so it only fires once, and set it's trigger in uSeconds.
timerAlarmWrite(timer, MS_TO_USEC(params.timeout), ONCE);
// Note: Interrupt needs to be attached before it can be enabled or disabled.
// Note: EDGE (true) is not supported, use LEVEL (false). Ref: #1713
// See: https://github.com/espressif/arduino-esp32/blob/caef4006af491130136b219c1205bdcf8f08bf2b/cores/esp32/esp32-hal-timer.c#L224-L227
timerAttachInterrupt(timer, &read_timeout, false);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#endif // ESP32
// Initialise state machine variables
@ -398,9 +417,13 @@ void IRrecv::disableIRIn(void) {
os_timer_disarm(&timer);
#endif // ESP8266
#if defined(ESP32)
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerEnd(timer);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timerAlarmDisable(timer);
timerDetachInterrupt(timer);
timerEnd(timer);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
#endif // ESP32
detachInterrupt(params.recvpin);
#endif // UNIT_TEST
@ -426,7 +449,11 @@ void IRrecv::resume(void) {
params.rawlen = 0;
params.overflow = false;
#if defined(ESP32)
#if ( defined(ESP_ARDUINO_VERSION_MAJOR) && (ESP_ARDUINO_VERSION_MAJOR >= 3) )
timerEnd(timer);
#else // ESP_ARDUINO_VERSION_MAJOR >= 3
timerAlarmDisable(timer);
#endif // ESP_ARDUINO_VERSION_MAJOR >= 3
gpio_intr_enable((gpio_num_t)params.recvpin);
#endif // ESP32
}

View File

@ -101,9 +101,16 @@ License along with NeoPixel. If not, see
#include "internal/NeoEspBitBangMethod.h"
#elif defined(ARDUINO_ARCH_ESP32)
#if ESP_IDF_VERSION_MAJOR < 5
#include "internal/NeoEsp32I2sMethod.h"
#include "internal/NeoEsp32RmtMethod.h"
#else
#if !defined(CONFIG_IDF_TARGET_ESP32C2)
#include "internal/NeoEsp32RmtMethod_idf5.h" // every other SOC
#else //CONFIG_IDF_TARGET_ESP32C2
#include "internal/NeoEsp32SpiMethod_idf5.h" // ESP32C2
#endif //CONFIG_IDF_TARGET_ESP32C2
#endif // ESP_IDF_VERSION_MAJOR
#include "internal/NeoEspBitBangMethod.h"
#include "internal/DotStarEsp32DmaSpiMethod.h"

View File

@ -29,12 +29,12 @@ License along with NeoPixel. If not, see
#include "driver/spi_master.h"
#if defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(HSPI_HOST)
#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST)
// HSPI_HOST depreciated in C3
#define HSPI_HOST SPI2_HOST
#endif
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
class Esp32VspiBus
{
public:
@ -52,7 +52,7 @@ public:
const static int ParallelBits = 1;
};
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
class Esp32Vspi2BitBus
{
public:
@ -70,7 +70,7 @@ public:
const static int ParallelBits = 2;
};
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
class Esp32Vspi4BitBus
{
public:
@ -174,7 +174,7 @@ public:
// If pins aren't specified, initialize bus with just the default SCK and MOSI pins for the SPI peripheral (no SS, no >1-bit pins)
void Initialize()
{
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
if (T_SPIBUS::SpiHostDevice == VSPI_HOST)
{
Initialize(SCK, -1, MOSI, -1, -1, -1);
@ -277,7 +277,7 @@ private:
int8_t _ssPin;
};
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
// Clock Speed and Default Definitions for DotStarEsp32DmaVspi
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz, Esp32VspiBus> DotStarEsp32DmaVspi40MhzMethod;
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz, Esp32VspiBus> DotStarEsp32DmaVspi20MhzMethod;
@ -303,7 +303,7 @@ typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz, Esp32HspiBus> DotStarEsp32DmaHspiHz
typedef DotStarEsp32DmaHspi10MhzMethod DotStarEsp32DmaHspiMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
// Clock Speed and Default Definitions for DotStarEsp32DmaVspi2Bit
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit40MhzMethod;
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz,Esp32Vspi2BitBus> DotStarEsp32DmaVspi2Bit20MhzMethod;
@ -329,7 +329,7 @@ typedef DotStarEsp32DmaSpiMethod<SpiSpeedHz,Esp32Hspi2BitBus> DotStarEsp32DmaHsp
typedef DotStarEsp32DmaHspi2Bit10MhzMethod DotStarEsp32DmaHspi2BitMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
// Clock Speed and Default Definitions for DotStarEsp32DmaVspi4Bit
typedef DotStarEsp32DmaSpiMethod<SpiSpeed40Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit40MhzMethod;
typedef DotStarEsp32DmaSpiMethod<SpiSpeed20Mhz,Esp32Vspi4BitBus> DotStarEsp32DmaVspi4Bit20MhzMethod;

View File

@ -20,7 +20,8 @@
#include "sdkconfig.h" // this sets useful config symbols, like CONFIG_IDF_TARGET_ESP32C3
// ESP32C3/S3 I2S is not supported yet due to significant changes to interface
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3)
#ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32S3) && !defined(CONFIG_IDF_TARGET_ESP32C2)
#include <string.h>
#include <stdio.h>
@ -495,5 +496,6 @@ size_t i2sWrite(uint8_t bus_num, uint8_t* data, size_t len, bool copy, bool free
}
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
#endif //ESP_IDF_VERSION_MAJOR < 5
#endif // defined(ARDUINO_ARCH_ESP32)

View File

@ -1,7 +1,10 @@
#pragma once
#include "sdkconfig.h" // this sets useful config symbols, like CONFIG_IDF_TARGET_ESP32C3
#ifndef CONFIG_SOC_RMT_TX_CANDIDATES_PER_GROUP // turn this off with something new from idf5.1
// ESP32C3 I2S is not supported yet due to significant changes to interface
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2)
#ifdef __cplusplus
extern "C" {
@ -38,5 +41,5 @@ bool i2sWriteDone(uint8_t bus_num);
#ifdef __cplusplus
}
#endif
#endif
#endif // ESP_IDF_VERSION_MAJOR < 5

View File

@ -12,7 +12,7 @@ enum NeoBusChannel
NeoBusChannel_0,
NeoBusChannel_1,
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
NeoBusChannel_2,
@ -35,7 +35,7 @@ enum NeoBusChannel
NeoBusChannel_7,
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
#endif // ARDUINO_ARCH_ESP32

View File

@ -26,12 +26,16 @@ License along with NeoPixel. If not, see
#pragma once
#if ESP_IDF_VERSION_MAJOR <= 4
// ESP32C3 I2S is not supported yet due to significant changes to interface
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C3)
extern "C"
{
#include <Arduino.h>
#if ESP_IDF_VERSION_MAJOR >= 5
#include <rom/gpio.h>
#endif
#include "Esp32_i2s.h"
}
@ -376,5 +380,5 @@ typedef NeoEsp32I2s1Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
typedef NeoEsp32I2s1400KbpsInvertedMethod Neo400KbpsInvertedMethod;
#endif // !defined(NEOPIXEL_ESP32_RMT_DEFAULT) && !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#endif
#endif // ESP_IDF_VERSION_MAJOR < 5

View File

@ -32,7 +32,7 @@ License along with NeoPixel. If not, see
#include "NeoBusChannel.h"
#include "NeoEsp32RmtMethod.h"
#ifdef ARDUINO_ARCH_ESP32
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C2)
// translate NeoPixelBuffer into RMT buffer

View File

@ -29,7 +29,7 @@ License along with NeoPixel. If not, see
#pragma once
#ifdef ARDUINO_ARCH_ESP32
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32C2)
/* General Reference documentation for the APIs used in this implementation
LOW LEVEL: (what is actually used)
@ -47,6 +47,9 @@ Esp32-hal-rmt.c
extern "C"
{
#if ESP_IDF_VERSION_MAJOR >= 5
#include <rom/gpio.h>
#endif
#include <driver/rmt.h>
}
@ -451,7 +454,7 @@ public:
const static rmt_channel_t RmtChannelNumber = RMT_CHANNEL_3;
};
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6)
class NeoEsp32RmtChannel4
{

View File

@ -0,0 +1,892 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp32.
A BIG thanks to Andreas Merkle for the investigation and implementation of
a workaround to the GCC bug that drops method attributes from template methods
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
#if defined(ARDUINO_ARCH_ESP32) && !defined(CONFIG_IDF_TARGET_ESP32C2)
/* General Reference documentation for the APIs used in this implementation
LOW LEVEL: (what is actually used)
DOCS: https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/rmt.html
EXAMPLE: https://github.com/espressif/esp-idf/blob/826ff7186ae07dc81e960a8ea09ebfc5304bfb3b/examples/peripherals/rmt_tx/main/rmt_tx_main.c
HIGHER LEVEL:
NO TRANSLATE SUPPORT so this was not used
NOTE: https://github.com/espressif/arduino-esp32/commit/50d142950d229b8fabca9b749dc4a5f2533bc426
Esp32-hal-rmt.h
Esp32-hal-rmt.c
*/
#include <Arduino.h>
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...);
extern "C"
{
#include <rom/gpio.h>
#include "driver/rmt_tx.h"
#include "driver/rmt_encoder.h"
#include "esp_check.h"
}
#define RMT_LED_STRIP_RESOLUTION_HZ 40000000 // 40MHz resolution - setting of the "old" driver
typedef struct {
uint32_t resolution; /*!< Encoder resolution, in Hz */
} led_strip_encoder_config_t;
typedef struct {
rmt_encoder_t base;
rmt_encoder_t *bytes_encoder;
rmt_encoder_t *copy_encoder;
int state;
rmt_symbol_word_t reset_code;
} rmt_led_strip_encoder_t;
static size_t rmt_encode_led_strip(rmt_encoder_t *encoder, rmt_channel_handle_t channel, const void *primary_data, size_t data_size, rmt_encode_state_t *ret_state)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_handle_t bytes_encoder = led_encoder->bytes_encoder;
rmt_encoder_handle_t copy_encoder = led_encoder->copy_encoder;
rmt_encode_state_t session_state = RMT_ENCODING_RESET;
rmt_encode_state_t state = RMT_ENCODING_RESET;
size_t encoded_symbols = 0;
switch (led_encoder->state) {
case 0: // send RGB data
encoded_symbols += bytes_encoder->encode(bytes_encoder, channel, primary_data, data_size, &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = 1; // switch to next state when current encoding session finished
}
if (session_state & RMT_ENCODING_MEM_FULL) {
// static_cast<AnimalFlags>(static_cast<int>(a) | static_cast<int>(b));
state = static_cast<rmt_encode_state_t>(static_cast<uint8_t>(state) | static_cast<uint8_t>(RMT_ENCODING_MEM_FULL));
goto out; // yield if there's no free space for encoding artifacts
}
// fall-through
case 1: // send reset code
encoded_symbols += copy_encoder->encode(copy_encoder, channel, &led_encoder->reset_code,
sizeof(led_encoder->reset_code), &session_state);
if (session_state & RMT_ENCODING_COMPLETE) {
led_encoder->state = RMT_ENCODING_RESET; // back to the initial encoding session
state = static_cast<rmt_encode_state_t>(static_cast<uint8_t>(state) | static_cast<uint8_t>(RMT_ENCODING_COMPLETE));
}
if (session_state & RMT_ENCODING_MEM_FULL) {
state = static_cast<rmt_encode_state_t>(static_cast<uint8_t>(state) | static_cast<uint8_t>(RMT_ENCODING_MEM_FULL));
goto out; // yield if there's no free space for encoding artifacts
}
}
out:
*ret_state = state;
return encoded_symbols;
}
static esp_err_t rmt_del_led_strip_encoder(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_del_encoder(led_encoder->bytes_encoder);
rmt_del_encoder(led_encoder->copy_encoder);
delete led_encoder;
return ESP_OK;
}
static esp_err_t rmt_led_strip_encoder_reset(rmt_encoder_t *encoder)
{
rmt_led_strip_encoder_t *led_encoder = __containerof(encoder, rmt_led_strip_encoder_t, base);
rmt_encoder_reset(led_encoder->bytes_encoder);
rmt_encoder_reset(led_encoder->copy_encoder);
led_encoder->state = RMT_ENCODING_RESET;
return ESP_OK;
}
esp_err_t rmt_new_led_strip_encoder(const led_strip_encoder_config_t *config, rmt_encoder_handle_t *ret_encoder, uint32_t bit0, uint32_t bit1)
{
const char* TAG = "TEST_RMT"; //TODO: Remove later
esp_err_t ret = ESP_OK;
rmt_led_strip_encoder_t *led_encoder = NULL;
uint32_t reset_ticks = config->resolution / 1000000 * 50 / 2; // reset code duration defaults to 50us
rmt_bytes_encoder_config_t bytes_encoder_config;
rmt_copy_encoder_config_t copy_encoder_config = {};
rmt_symbol_word_t reset_code_config;
ESP_GOTO_ON_FALSE(config && ret_encoder, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
led_encoder = new rmt_led_strip_encoder_t();
ESP_GOTO_ON_FALSE(led_encoder, ESP_ERR_NO_MEM, err, TAG, "no mem for led strip encoder");
led_encoder->base.encode = rmt_encode_led_strip;
led_encoder->base.del = rmt_del_led_strip_encoder;
led_encoder->base.reset = rmt_led_strip_encoder_reset;
bytes_encoder_config.bit0.val = bit0;
bytes_encoder_config.bit1.val = bit1;
bytes_encoder_config.flags.msb_first = 1; // WS2812 transfer bit order: G7...G0R7...R0B7...B0 - TODO: more checks
ESP_GOTO_ON_ERROR(rmt_new_bytes_encoder(&bytes_encoder_config, &led_encoder->bytes_encoder), err, TAG, "create bytes encoder failed");
ESP_GOTO_ON_ERROR(rmt_new_copy_encoder(&copy_encoder_config, &led_encoder->copy_encoder), err, TAG, "create copy encoder failed");
reset_code_config.level0 = 0;
reset_code_config.duration0 = reset_ticks;
reset_code_config.level1 = 0;
reset_code_config.duration1 = reset_ticks;
led_encoder->reset_code = reset_code_config;
*ret_encoder = &led_encoder->base;
return ret;
err:
// AddLog(2,"RMT:could not init led decoder");
if (led_encoder) {
if (led_encoder->bytes_encoder) {
rmt_del_encoder(led_encoder->bytes_encoder);
}
if (led_encoder->copy_encoder) {
rmt_del_encoder(led_encoder->copy_encoder);
}
delete led_encoder;
}
return ret;
}
#define NEOPIXELBUS_RMT_INT_FLAGS (ESP_INTR_FLAG_LOWMED)
class NeoEsp32RmtSpeed
{
public:
// next section is probably not needed anymore for IDF 5.1
// ClkDiv of 2 provides for good resolution and plenty of reset resolution; but
// a ClkDiv of 1 will provide enough space for the longest reset and does show
// little better pulse accuracy
const static uint8_t RmtClockDivider = 2;
inline constexpr static uint32_t FromNs(uint32_t ns)
{
return ns / NsPerRmtTick;
}
protected:
const static uint32_t RmtCpu = 80000000L; // 80 mhz RMT clock
const static uint32_t NsPerSecond = 1000000000L;
const static uint32_t RmtTicksPerSecond = (RmtCpu / RmtClockDivider);
const static uint32_t NsPerRmtTick = (NsPerSecond / RmtTicksPerSecond); // about 25
// end of deprecated section
};
class NeoEsp32RmtSpeedBase : public NeoEsp32RmtSpeed
{
public:
// this is used rather than the rmt_symbol_word_t as you can't correctly initialize
// it as a static constexpr within the template
inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow)
{
return (FromNs(nsLow) << 16) | (1 << 15) | (FromNs(nsHigh));
}
};
class NeoEsp32RmtInvertedSpeedBase : public NeoEsp32RmtSpeed
{
public:
// this is used rather than the rmt_symbol_word_t as you can't correctly initialize
// it as a static constexpr within the template
inline constexpr static uint32_t Item32Val(uint16_t nsHigh, uint16_t nsLow)
{
return (FromNs(nsLow) << 16) | (1 << 31) | (FromNs(nsHigh));
}
};
class NeoEsp32RmtSpeedWs2811 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950); // TODO: DRAM_ATTR debatable everywhere
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
};
class NeoEsp32RmtSpeedWs2812x : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
};
class NeoEsp32RmtSpeedSk6812 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
};
// normal is inverted signal
class NeoEsp32RmtSpeedTm1814 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
};
// normal is inverted signal
class NeoEsp32RmtSpeedTm1829 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 900);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 400);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
};
// normal is inverted signal
class NeoEsp32RmtSpeedTm1914 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
};
class NeoEsp32RmtSpeed800Kbps : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
};
class NeoEsp32RmtSpeed400Kbps : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
};
class NeoEsp32RmtSpeedApa106 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(350, 1350);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1350, 350);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
};
class NeoEsp32RmtSpeedTx1812 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 600);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(600, 300);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
};
class NeoEsp32RmtInvertedSpeedWs2811 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 950);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(900, 350);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
};
class NeoEsp32RmtInvertedSpeedWs2812x : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(300000); // 300us
};
class NeoEsp32RmtInvertedSpeedSk6812 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
};
// normal is inverted signal
class NeoEsp32RmtInvertedSpeedTm1814 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
};
// normal is inverted signal
class NeoEsp32RmtInvertedSpeedTm1829 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 900);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 400);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
};
// normal is inverted signal
class NeoEsp32RmtInvertedSpeedTm1914 : public NeoEsp32RmtSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(360, 890);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(720, 530);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(200000); // 200us
};
class NeoEsp32RmtInvertedSpeed800Kbps : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(400, 850);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(800, 450);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
};
class NeoEsp32RmtInvertedSpeed400Kbps : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(800, 1700);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1600, 900);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
};
class NeoEsp32RmtInvertedSpeedApa106 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(350, 1350);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(1350, 350);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(50000); // 50us
};
class NeoEsp32RmtInvertedSpeedTx1812 : public NeoEsp32RmtInvertedSpeedBase
{
public:
const static DRAM_ATTR uint32_t RmtBit0 = Item32Val(300, 600);
const static DRAM_ATTR uint32_t RmtBit1 = Item32Val(600, 300);
const static DRAM_ATTR uint16_t RmtDurationReset = FromNs(80000); // 80us
};
class NeoEsp32RmtChannel0
{
public:
NeoEsp32RmtChannel0() {};
rmt_channel_handle_t RmtChannelNumber = NULL;
};
class NeoEsp32RmtChannel1
{
public:
NeoEsp32RmtChannel1() {};
rmt_channel_handle_t RmtChannelNumber = NULL;
};
#if !defined(CONFIG_IDF_TARGET_ESP32C6) // C6 only 2 RMT channels ??
class NeoEsp32RmtChannel2
{
public:
NeoEsp32RmtChannel2() {};
rmt_channel_handle_t RmtChannelNumber = NULL;
};
class NeoEsp32RmtChannel3
{
public:
NeoEsp32RmtChannel3() {};
protected:
rmt_channel_handle_t RmtChannelNumber = NULL;
};
#endif // !defined(CONFIG_IDF_TARGET_ESP32C6)
#if !defined(CONFIG_IDF_TARGET_ESP32S2) && !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6)
class NeoEsp32RmtChannel4
{
public:
NeoEsp32RmtChannel4() {};
rmt_channel_handle_t RmtChannelNumber = NULL;
};
class NeoEsp32RmtChannel5
{
public:
NeoEsp32RmtChannel5() {};
rmt_channel_handle_t RmtChannelNumber = NULL;
};
class NeoEsp32RmtChannel6
{
public:
NeoEsp32RmtChannel6() {};
rmt_channel_handle_t RmtChannelNumber = NULL;
};
class NeoEsp32RmtChannel7
{
public:
NeoEsp32RmtChannel7() {};
rmt_channel_handle_t RmtChannelNumber = NULL;
};
#endif
// dynamic channel support
class NeoEsp32RmtChannelN
{
public:
NeoEsp32RmtChannelN(NeoBusChannel channel) :
RmtChannelNumber(RmtChannelNumber)
{
RmtChannelNumber = NULL;
};
NeoEsp32RmtChannelN() = delete; // no default constructor
rmt_channel_handle_t RmtChannelNumber = NULL;
};
template<typename T_SPEED, typename T_CHANNEL> class NeoEsp32RmtMethodBase
{
public:
typedef NeoNoSettings SettingsObject;
NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
_pin(pin)
{
construct();
}
NeoEsp32RmtMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
_sizeData(pixelCount* elementSize + settingsSize),
_pin(pin),
_channel(channel)
{
construct();
}
~NeoEsp32RmtMethodBase()
{
// wait until the last send finishes before destructing everything
// arbitrary time out of 10 seconds
ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_tx_wait_all_done(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS));
ESP_ERROR_CHECK( rmt_del_channel(_channel.RmtChannelNumber));
gpio_matrix_out(_pin, 0x100, false, false);
pinMode(_pin, INPUT);
free(_dataEditing);
free(_dataSending);
}
bool IsReadyToUpdate() const
{
return (ESP_OK == rmt_tx_wait_all_done(_channel.RmtChannelNumber, 0));
}
void Initialize()
{
esp_err_t ret = ESP_OK;
rmt_tx_channel_config_t config = {};
config.clk_src = RMT_CLK_SRC_DEFAULT;
config.gpio_num = static_cast<gpio_num_t>(_pin);
config.mem_block_symbols = 64; // memory block size, 64 * 4 = 256 Bytes
config.resolution_hz = RMT_LED_STRIP_RESOLUTION_HZ; // 1 MHz tick resolution, i.e., 1 tick = 1 µs
config.trans_queue_depth = 4; // set the number of transactions that can pend in the background
config.flags.invert_out = false; // do not invert output signal
config.flags.with_dma = false; // do not need DMA backend
ret += rmt_new_tx_channel(&config,&_channel.RmtChannelNumber);
led_strip_encoder_config_t encoder_config = {};
encoder_config.resolution = RMT_LED_STRIP_RESOLUTION_HZ;
_tx_config.loop_count = 0; //no loop
ret += rmt_new_led_strip_encoder(&encoder_config, &_led_encoder, T_SPEED::RmtBit0, T_SPEED::RmtBit1);
// ESP_LOGI(TAG, "Enable RMT TX channel");
ret += rmt_enable(_channel.RmtChannelNumber);
AddLog(2,"RMT:initialized with error code: %u on pin: %u",ret, _pin);
}
void Update(bool maintainBufferConsistency)
{
// AddLog(2,"..");
// wait for not actively sending data
// this will time out at 10 seconds, an arbitrarily long period of time
// and do nothing if this happens
if (ESP_OK == ESP_ERROR_CHECK_WITHOUT_ABORT(rmt_tx_wait_all_done(_channel.RmtChannelNumber, 10000 / portTICK_PERIOD_MS)))
{
// AddLog(2,"__ %u", _sizeData);
// now start the RMT transmit with the editing buffer before we swap
esp_err_t ret = rmt_transmit(_channel.RmtChannelNumber, _led_encoder, _dataEditing, _sizeData, &_tx_config); // 3 for _sizeData
// AddLog(2,"rmt_transmit: %u", ret);
if (maintainBufferConsistency)
{
// copy editing to sending,
// this maintains the contract that "colors present before will
// be the same after", otherwise GetPixelColor will be inconsistent
memcpy(_dataSending, _dataEditing, _sizeData);
}
// swap so the user can modify without affecting the async operation
std::swap(_dataSending, _dataEditing);
}
}
uint8_t* getData() const
{
return _dataEditing;
};
size_t getDataSize() const
{
return _sizeData;
}
void applySettings(const SettingsObject& settings)
{
}
private:
const size_t _sizeData; // Size of '_data*' buffers
const uint8_t _pin; // output pin number
rmt_transmit_config_t _tx_config = {};
rmt_encoder_handle_t _led_encoder = nullptr;
T_CHANNEL _channel; // holds instance for multi channel support
// Holds data stream which include LED color values and other settings as needed
uint8_t* _dataEditing; // exposed for get and set
uint8_t* _dataSending; // used for async send using RMT
void construct()
{
// AddLog(2,"RMT:construct");
_dataEditing = static_cast<uint8_t*>(malloc(_sizeData));
// data cleared later in Begin()
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
// no need to initialize it, it gets overwritten on every send
}
};
// normal
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannelN> NeoEsp32RmtNSk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannelN> NeoEsp32RmtNApa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannelN> NeoEsp32RmtNTx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6)
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6400KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2811Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2812xMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Sk6812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1814Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1829, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1829Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTm1914, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1914Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeedTx1812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tx1812Method;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsMethod;
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C3)
// inverted
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannelN> NeoEsp32RmtNWs2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannelN> NeoEsp32RmtNSk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannelN> NeoEsp32RmtNTm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannelN> NeoEsp32RmtNApa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannelN> NeoEsp32RmtNTx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannelN> NeoEsp32RmtN400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel0> NeoEsp32Rmt0Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel0> NeoEsp32Rmt0Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel0> NeoEsp32Rmt0Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel0> NeoEsp32Rmt0400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel1> NeoEsp32Rmt1Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel1> NeoEsp32Rmt1Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel1> NeoEsp32Rmt1Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel1> NeoEsp32Rmt1400KbpsInvertedMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6)
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel2> NeoEsp32Rmt2Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel2> NeoEsp32Rmt2Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel2> NeoEsp32Rmt2Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel2> NeoEsp32Rmt2400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel3> NeoEsp32Rmt3Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel3> NeoEsp32Rmt3Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel3> NeoEsp32Rmt3Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel3> NeoEsp32Rmt3400KbpsInvertedMethod;
#if !defined(CONFIG_IDF_TARGET_ESP32S2)
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel4> NeoEsp32Rmt4Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel4> NeoEsp32Rmt4Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel4> NeoEsp32Rmt4Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel4> NeoEsp32Rmt4400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel5> NeoEsp32Rmt5Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel5> NeoEsp32Rmt5Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel5> NeoEsp32Rmt5Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel5> NeoEsp32Rmt5400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel6> NeoEsp32Rmt6Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel6> NeoEsp32Rmt6Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel6> NeoEsp32Rmt6Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel6> NeoEsp32Rmt6400KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2811, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2811InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedWs2812x, NeoEsp32RmtChannel7> NeoEsp32Rmt7Ws2812xInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedSk6812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Sk6812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1814, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1814InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1829, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1829InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTm1914, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tm1914InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedApa106, NeoEsp32RmtChannel7> NeoEsp32Rmt7Apa106InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeedTx1812, NeoEsp32RmtChannel7> NeoEsp32Rmt7Tx1812InvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed800Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7800KbpsInvertedMethod;
typedef NeoEsp32RmtMethodBase<NeoEsp32RmtInvertedSpeed400Kbps, NeoEsp32RmtChannel7> NeoEsp32Rmt7400KbpsInvertedMethod;
#endif // !defined(CONFIG_IDF_TARGET_ESP32S2)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C6)
#if defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
// Normally I2s method is the default, defining NEOPIXEL_ESP32_RMT_DEFAULT
// will switch to use RMT as the default method
// The ESP32S2 & ESP32C3 will always defualt to RMT
#if defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
// RMT channel 1 method is the default method for Esp32S2 & Esp32C3
typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2813Method;
typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2812xMethod;
typedef NeoEsp32Rmt1800KbpsMethod NeoWs2812Method;
typedef NeoEsp32Rmt1Ws2812xMethod NeoWs2811Method;
typedef NeoEsp32Rmt1Sk6812Method NeoSk6812Method;
typedef NeoEsp32Rmt1Tm1814Method NeoTm1814Method;
typedef NeoEsp32Rmt1Tm1829Method NeoTm1829Method;
typedef NeoEsp32Rmt1Tm1914Method NeoTm1914Method;
typedef NeoEsp32Rmt1Sk6812Method NeoLc8812Method;
typedef NeoEsp32Rmt1Apa106Method NeoApa106Method;
typedef NeoEsp32Rmt1Tx1812Method NeoTx1812Method;
typedef NeoEsp32Rmt1Ws2812xMethod Neo800KbpsMethod;
typedef NeoEsp32Rmt1400KbpsMethod Neo400KbpsMethod;
typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2813InvertedMethod;
typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
typedef NeoEsp32Rmt1Ws2812xInvertedMethod NeoWs2811InvertedMethod;
typedef NeoEsp32Rmt1800KbpsInvertedMethod NeoWs2812InvertedMethod;
typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoSk6812InvertedMethod;
typedef NeoEsp32Rmt1Tm1814InvertedMethod NeoTm1814InvertedMethod;
typedef NeoEsp32Rmt1Tm1829InvertedMethod NeoTm1829InvertedMethod;
typedef NeoEsp32Rmt1Tm1914InvertedMethod NeoTm1914InvertedMethod;
typedef NeoEsp32Rmt1Sk6812InvertedMethod NeoLc8812InvertedMethod;
typedef NeoEsp32Rmt1Apa106InvertedMethod NeoApa106InvertedMethod;
typedef NeoEsp32Rmt1Tx1812InvertedMethod NeoTx1812InvertedMethod;
typedef NeoEsp32Rmt1Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
typedef NeoEsp32Rmt1400KbpsInvertedMethod Neo400KbpsInvertedMethod;
#else // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3)
// RMT channel 6 method is the default method for Esp32
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2813Method;
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2812xMethod;
typedef NeoEsp32Rmt6800KbpsMethod NeoWs2812Method;
typedef NeoEsp32Rmt6Ws2812xMethod NeoWs2811Method;
typedef NeoEsp32Rmt6Sk6812Method NeoSk6812Method;
typedef NeoEsp32Rmt6Tm1814Method NeoTm1814Method;
typedef NeoEsp32Rmt6Tm1829Method NeoTm1829Method;
typedef NeoEsp32Rmt6Tm1914Method NeoTm1914Method;
typedef NeoEsp32Rmt6Sk6812Method NeoLc8812Method;
typedef NeoEsp32Rmt6Apa106Method NeoApa106Method;
typedef NeoEsp32Rmt6Tx1812Method NeoTx1812Method;
typedef NeoEsp32Rmt6Ws2812xMethod Neo800KbpsMethod;
typedef NeoEsp32Rmt6400KbpsMethod Neo400KbpsMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2813InvertedMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2812xInvertedMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod NeoWs2811InvertedMethod;
typedef NeoEsp32Rmt6800KbpsInvertedMethod NeoWs2812InvertedMethod;
typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoSk6812InvertedMethod;
typedef NeoEsp32Rmt6Tm1814InvertedMethod NeoTm1814InvertedMethod;
typedef NeoEsp32Rmt6Tm1829InvertedMethod NeoTm1829InvertedMethod;
typedef NeoEsp32Rmt6Tm1914InvertedMethod NeoTm1914InvertedMethod;
typedef NeoEsp32Rmt6Sk6812InvertedMethod NeoLc8812InvertedMethod;
typedef NeoEsp32Rmt6Apa106InvertedMethod NeoApa106InvertedMethod;
typedef NeoEsp32Rmt6Tx1812InvertedMethod NeoTx1812InvertedMethod;
typedef NeoEsp32Rmt6Ws2812xInvertedMethod Neo800KbpsInvertedMethod;
typedef NeoEsp32Rmt6400KbpsInvertedMethod Neo400KbpsInvertedMethod;
#endif // defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
#endif // defined(NEOPIXEL_ESP32_RMT_DEFAULT) || defined(CONFIG_IDF_TARGET_ESP32S2) || defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C6)
#endif

View File

@ -0,0 +1,504 @@
/*-------------------------------------------------------------------------
NeoPixel library helper functions for Esp32.
Adaption of Espressif's component library code by Christian Baars
Written by Michael C. Miller.
I invest time and resources providing this open source code,
please support me by dontating (see https://github.com/Makuna/NeoPixelBus)
-------------------------------------------------------------------------
This file is not yet part of the Makuna/NeoPixelBus library.
NeoPixelBus is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
NeoPixelBus is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with NeoPixel. If not, see
<http://www.gnu.org/licenses/>.
-------------------------------------------------------------------------*/
#pragma once
#if defined(ARDUINO_ARCH_ESP32)
#if (defined(CONFIG_IDF_TARGET_ESP32C3) || defined(CONFIG_IDF_TARGET_ESP32C2) || defined(CONFIG_IDF_TARGET_ESP32C6)) && !defined(HSPI_HOST)
// HSPI_HOST depreciated in C3
#define HSPI_HOST SPI2_HOST
#endif
#include <Arduino.h>
extern void AddLog(uint32_t loglevel, PGM_P formatP, ...); // TODO: Remove all Addlogs
extern "C"
{
#include <rom/gpio.h>
#include "esp_rom_gpio.h"
#include "driver/spi_master.h"
#include "esp_check.h"
}
#define LED_STRIP_SPI_DEFAULT_RESOLUTION (25 * 100 * 1000) // 2.5MHz resolution
#define LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE 4
#define SPI_BYTES_PER_COLOR_BYTE 3
#define SPI_BITS_PER_COLOR_BYTE (SPI_BYTES_PER_COLOR_BYTE * 8)
static const char *TAG = "led_strip_spi"; // TODO: Remove all TAG log stuff
typedef enum {
LED_MODEL_WS2812, /*!< LED strip model: WS2812 */
LED_MODEL_SK6812, /*!< LED strip model: SK6812 */
LED_MODEL_INVALID /*!< Invalid LED strip model */
} led_model_t;
typedef enum {
LED_PIXEL_FORMAT_GRB, /*!< Pixel format: GRB */
LED_PIXEL_FORMAT_GRBW, /*!< Pixel format: GRBW */
LED_PIXEL_FORMAT_INVALID /*!< Invalid pixel format */
} led_pixel_format_t;
typedef struct {
spi_host_device_t spi_host;
spi_device_handle_t spi_device;
uint32_t strip_len;
uint8_t bytes_per_pixel;
uint8_t pixel_buf[];
} led_strip_spi_obj;
/**
* @brief LED Strip Configuration
*/
typedef struct {
int strip_gpio_num; /*!< GPIO number that used by LED strip */
uint32_t max_leds; /*!< Maximum LEDs in a single strip */
led_pixel_format_t led_pixel_format; /*!< LED pixel format */
led_model_t led_model; /*!< LED model */
struct {
uint32_t invert_out: 1; /*!< Invert output signal */
} flags;
} led_strip_config_t;
typedef struct {
spi_clock_source_t clk_src; /*!< SPI clock source */
spi_host_device_t spi_bus; /*!< SPI bus ID. Which buses are available depends on the specific chip */
struct {
uint32_t with_dma: 1; /*!< Use DMA to transmit data */
} flags;
} led_strip_spi_config_t;
class NeoEsp32SpiSpeed
{
public:
protected:
// end of deprecated section
};
class NeoEsp32SpiSpeedBase : public NeoEsp32SpiSpeed
{
public:
};
class NeoEsp32SpiInvertedSpeedBase : public NeoEsp32SpiSpeed
{
public:
};
class NeoEsp32SpiSpeedWs2811 : public NeoEsp32SpiSpeedBase
{
public:
};
class NeoEsp32SpiSpeedWs2812x : public NeoEsp32SpiSpeedBase
{
public:
static const uint8_t bytes_per_pixel = 3;
};
class NeoEsp32SpiSpeedSk6812 : public NeoEsp32SpiSpeedBase
{
public:
static const uint8_t bytes_per_pixel = 4;
};
class NeoEsp32SpiSpeed400Kbps : public NeoEsp32SpiSpeedBase
{
public:
};
class NeoEsp32SpiSpeedApa106 : public NeoEsp32SpiSpeedBase
{
public:
};
class NeoEsp32SpiSpeedTx1812 : public NeoEsp32SpiSpeedBase
{
public:
};
class NeoEsp32SpiInvertedSpeedWs2811 : public NeoEsp32SpiInvertedSpeedBase
{
public:
};
class NeoEsp32SpiInvertedSpeedWs2812x : public NeoEsp32SpiInvertedSpeedBase
{
public:
};
class NeoEsp32SpiInvertedSpeedSk6812 : public NeoEsp32SpiInvertedSpeedBase
{
public:
};
class NeoEsp32SpiInvertedSpeed800Kbps : public NeoEsp32SpiInvertedSpeedBase
{
public:
};
class NeoEsp32SpiInvertedSpeed400Kbps : public NeoEsp32SpiInvertedSpeedBase
{
public:
};
class NeoEsp32SpiInvertedSpeedApa106 : public NeoEsp32SpiInvertedSpeedBase
{
public:
};
class NeoEsp32SpiInvertedSpeedTx1812 : public NeoEsp32SpiInvertedSpeedBase
{
public:
};
class NeoEsp32SpiChannel
{
public:
};
template<typename T_SPEED, typename T_CHANNEL> class NeoEsp32SpiMethodBase
{
public:
typedef NeoNoSettings SettingsObject;
NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize) :
_sizeData(pixelCount * elementSize + settingsSize),
// _pixelCount(pixelCount),
_pin(pin)
{
_pixelCount = pixelCount;
construct();
}
NeoEsp32SpiMethodBase(uint8_t pin, uint16_t pixelCount, size_t elementSize, size_t settingsSize, NeoBusChannel channel) :
_sizeData(pixelCount* elementSize + settingsSize),
// _pixelCount(pixelCount),
_pin(pin)
// _channel(channel) // TODO: Refactor this somehow
{
_pixelCount = pixelCount;
construct();
}
~NeoEsp32SpiMethodBase()
{
// wait until the last send finishes before destructing everything
// arbitrary time out of 10 seconds
gpio_matrix_out(_pin, 0x100, false, false);
pinMode(_pin, INPUT);
spi_bus_remove_device(_spi_strip->spi_device);
spi_bus_free(_spi_strip->spi_host);
free(_spi_strip);
free(_dataEditing);
free(_dataSending);
}
bool IsReadyToUpdate() const
{
return true; // TODO
}
void Initialize()
{
esp_err_t ret = ESP_OK;
uint8_t bytes_per_pixel = T_SPEED::bytes_per_pixel;
uint32_t mem_caps = MALLOC_CAP_DEFAULT;
spi_clock_source_t clk_src = SPI_CLK_SRC_DEFAULT;
spi_bus_config_t spi_bus_cfg;
spi_device_interface_config_t spi_dev_cfg;
bool with_dma = true; /// TODO: pass value or compute based on pixelcount
int clock_resolution_khz = 0;
// ESP_GOTO_ON_FALSE(led_config && spi_config && ret_strip, ESP_ERR_INVALID_ARG, err, TAG, "invalid argument");
// ESP_GOTO_ON_FALSE(led_config->led_pixel_format < LED_PIXEL_FORMAT_INVALID, ESP_ERR_INVALID_ARG, err, TAG, "invalid led_pixel_format");
// if ( LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRBW) { // TODO
// bytes_per_pixel = 4;
// } else if (LED_PIXEL_FORMAT_GRB == LED_PIXEL_FORMAT_GRB) {
// bytes_per_pixel = 3;
// } else {
// assert(false);
// }
if (with_dma) { // TODO
// DMA buffer must be placed in internal SRAM
mem_caps |= MALLOC_CAP_INTERNAL | MALLOC_CAP_DMA;
}
_spi_strip = (led_strip_spi_obj *)heap_caps_calloc(1, sizeof(led_strip_spi_obj) + _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE, mem_caps);
ESP_GOTO_ON_FALSE(_spi_strip, ESP_ERR_NO_MEM, err, TAG, "no mem for spi strip");
_spi_strip->spi_host = SPI2_HOST;
// for backward compatibility, if the user does not set the clk_src, use the default value
// if (clk_src) {
// clk_src = spi_config->clk_src;
// }
spi_bus_cfg = {
.mosi_io_num = _pin,
//Only use MOSI to generate the signal, set -1 when other pins are not used.
.miso_io_num = -1,
.sclk_io_num = -1,
.quadwp_io_num = -1,
.quadhd_io_num = -1,
.max_transfer_sz = _pixelCount * bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE,
};
ESP_GOTO_ON_ERROR(spi_bus_initialize(_spi_strip->spi_host, &spi_bus_cfg, with_dma ? SPI_DMA_CH_AUTO : SPI_DMA_DISABLED), err, TAG, "create SPI bus failed");
// if (led_config->flags.invert_out == true) {
// esp_rom_gpio_connect_out_signal(_pin, spi_periph_signal[_spi_strip->spi_host].spid_out, true, false);
// }
spi_dev_cfg = {
.command_bits = 0,
.address_bits = 0,
.dummy_bits = 0,
.mode = 0,
//set -1 when CS is not used
.clock_source = clk_src,
.clock_speed_hz = LED_STRIP_SPI_DEFAULT_RESOLUTION,
.spics_io_num = -1,
.queue_size = LED_STRIP_SPI_DEFAULT_TRANS_QUEUE_SIZE,
};
ESP_GOTO_ON_ERROR(spi_bus_add_device(_spi_strip->spi_host, &spi_dev_cfg, &_spi_strip->spi_device), err, TAG, "Failed to add spi device");
spi_device_get_actual_freq(_spi_strip->spi_device, &clock_resolution_khz);
// TODO: ideally we should decide the SPI_BYTES_PER_COLOR_BYTE by the real clock resolution
// But now, let's fixed the resolution, the downside is, we don't support a clock source whose frequency is not multiple of LED_STRIP_SPI_DEFAULT_RESOLUTION
ESP_GOTO_ON_FALSE(clock_resolution_khz == LED_STRIP_SPI_DEFAULT_RESOLUTION / 1000, ESP_ERR_NOT_SUPPORTED, err,
TAG, "unsupported clock resolution:%dKHz", clock_resolution_khz);
_spi_strip->bytes_per_pixel = bytes_per_pixel;
_spi_strip->strip_len = _pixelCount;
AddLog(2,"SPI:initialized with error code: %u on pin: %u",ret, _pin);
return;
err:
if (_spi_strip) {
if (_spi_strip->spi_device) {
spi_bus_remove_device(_spi_strip->spi_device);
}
if (_spi_strip->spi_host) {
spi_bus_free(_spi_strip->spi_host);
}
free(_spi_strip);
}
AddLog(2,"SPI-Error:initialized with error code: %u on pin: %u",ret, _pin);
return;
}
void Update(bool maintainBufferConsistency)
{
// AddLog(2,"..");
// wait for not actively sending data
// this will time out at 10 seconds, an arbitrarily long period of time
// and do nothing if this happens
// if READY
{
// AddLog(2,"__ %u", _sizeData);
// now start the SPI transmit with the editing buffer before we swap
led_strip_transmit_RGB_buffer(_dataEditing, _sizeData, T_SPEED::bytes_per_pixel);
if (maintainBufferConsistency)
{
// copy editing to sending,
// this maintains the contract that "colors present before will
// be the same after", otherwise GetPixelColor will be inconsistent
memcpy(_dataSending, _dataEditing, _sizeData);
}
// swap so the user can modify without affecting the async operation
std::swap(_dataSending, _dataEditing);
}
}
uint8_t* getData() const
{
return _dataEditing;
};
size_t getDataSize() const
{
return _sizeData;
}
void applySettings(const SettingsObject& settings)
{
}
private:
const size_t _sizeData; // Size of '_data*' buffers
int16_t _pixelCount;
const uint8_t _pin; // output pin number
T_CHANNEL _channel; // not really used here
led_strip_spi_obj *_spi_strip;
// Holds data stream which include LED color values and other settings as needed
uint8_t* _dataEditing; // exposed for get and set
uint8_t* _dataSending; // used for async send using RMT - TODO: Check if this useful for SPI
void construct()
{
_dataEditing = static_cast<uint8_t*>(malloc(_sizeData));
// data cleared later in Begin()
_dataSending = static_cast<uint8_t*>(malloc(_sizeData));
// no need to initialize it, it gets overwritten on every send
}
// please make sure to zero-initialize the buf before calling this function
void __led_strip_spi_bit(uint8_t data, uint8_t *buf)
{
// Each color of 1 bit is represented by 3 bits of SPI, low_level:100 ,high_level:110
// So a color byte occupies 3 bytes of SPI.
*(buf + 2) |= data & BIT(0) ? BIT(2) | BIT(1) : BIT(2);
*(buf + 2) |= data & BIT(1) ? BIT(5) | BIT(4) : BIT(5);
*(buf + 2) |= data & BIT(2) ? BIT(7) : 0x00;
*(buf + 1) |= BIT(0);
*(buf + 1) |= data & BIT(3) ? BIT(3) | BIT(2) : BIT(3);
*(buf + 1) |= data & BIT(4) ? BIT(6) | BIT(5) : BIT(6);
*(buf + 0) |= data & BIT(5) ? BIT(1) | BIT(0) : BIT(1);
*(buf + 0) |= data & BIT(6) ? BIT(4) | BIT(3) : BIT(4);
*(buf + 0) |= data & BIT(7) ? BIT(7) | BIT(6) : BIT(7);
}
esp_err_t led_strip_spi_set_pixel(uint32_t index, uint32_t red, uint32_t green, uint32_t blue)
{
if(index >= _spi_strip->strip_len) return ESP_FAIL;
// LED_PIXEL_FORMAT_GRB takes 72bits(9bytes)
uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
__led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]);
__led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]);
__led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]);
if (_spi_strip->bytes_per_pixel > 3) {
__led_strip_spi_bit(0, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]);
}
return ESP_OK;
}
esp_err_t led_strip_spi_set_pixel_rgbw(uint32_t index, uint32_t red, uint32_t green, uint32_t blue, uint32_t white)
{
// LED_PIXEL_FORMAT_GRBW takes 96bits(12bytes)
uint32_t start = index * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE;
// SK6812 component order is GRBW
memset(_spi_strip->pixel_buf + start, 0, _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
__led_strip_spi_bit(green, &_spi_strip->pixel_buf[start]);
__led_strip_spi_bit(red, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE]);
__led_strip_spi_bit(blue, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 2]);
__led_strip_spi_bit(white, &_spi_strip->pixel_buf[start + SPI_BYTES_PER_COLOR_BYTE * 3]);
return ESP_OK;
}
esp_err_t led_strip_spi_clear()
{
//Write zero to turn off all leds
memset(_spi_strip->pixel_buf, 0, _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BYTES_PER_COLOR_BYTE);
uint8_t *buf = _spi_strip->pixel_buf;
for (int index = 0; index < _spi_strip->strip_len * _spi_strip->bytes_per_pixel; index++) {
__led_strip_spi_bit(0, buf);
buf += SPI_BYTES_PER_COLOR_BYTE;
}
return led_strip_spi_refresh();
}
esp_err_t led_strip_spi_refresh()
{
spi_transaction_t tx_conf;
memset(&tx_conf, 0, sizeof(tx_conf));
tx_conf.length = _spi_strip->strip_len * _spi_strip->bytes_per_pixel * SPI_BITS_PER_COLOR_BYTE;
tx_conf.tx_buffer = _spi_strip->pixel_buf;
tx_conf.rx_buffer = NULL;
spi_device_transmit(_spi_strip->spi_device, &tx_conf); // TODO -check
return ESP_OK;
}
void led_strip_transmit_RGB_buffer(uint8_t * buffer, size_t size, uint8_t bytes_per_pixel)
{
for (int i = 0; i < size; i+=bytes_per_pixel) {
led_strip_spi_set_pixel(i/bytes_per_pixel, buffer[i+1], buffer[i], buffer[i+2]); //GRB -> RGB
}
/* Refresh the strip to send data */
led_strip_spi_refresh();
}
};
// normal
typedef NeoEsp32SpiMethodBase<NeoEsp32SpiSpeedWs2812x, NeoEsp32SpiChannel> NeoEsp32SpiN800KbpsMethod;
typedef NeoEsp32SpiMethodBase<NeoEsp32SpiSpeedSk6812, NeoEsp32SpiChannel> NeoEsp32SpiNSk6812Method;
// SPI channel method is the default method for Esp32C2
#ifdef CONFIG_IDF_TARGET_ESP32C2
typedef NeoEsp32SpiSpeedWs2812x NeoWs2813Method;
typedef NeoEsp32SpiSpeedWs2812x NeoWs2812xMethod;
typedef NeoEsp32SpiSpeedSk6812 NeoSk6812Method;
#endif //CONFIG_IDF_TARGET_ESP32C2
#endif

View File

@ -28,8 +28,11 @@ License along with NeoPixel. If not, see
#include <Arduino.h>
// ESP32C3 I2S is not supported yet
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
// ESP32C3 I2S is not supported yet
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
#if !defined(ARDUINO_ARCH_ESP8266)
#include "soc/gpio_periph.h"
#endif
static inline uint32_t getCycleCount(void)
{
@ -154,5 +157,5 @@ void IRAM_ATTR NeoEspBitBangBase_send_pixels_inv(uint8_t* pixels, uint8_t* end,
}
}
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
#endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)

View File

@ -29,7 +29,7 @@ License along with NeoPixel. If not, see
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
// ESP32C3 I2S is not supported yet
#if !defined(CONFIG_IDF_TARGET_ESP32C3)
#if !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
#if defined(ARDUINO_ARCH_ESP8266)
#include <eagle_soc.h>
@ -377,5 +377,5 @@ typedef NeoEsp8266BitBangSk6812InvertedMethod NeoEsp8266BitBangLc8812InvertedMet
// ESP bitbang doesn't have defaults and should avoided except for testing
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3)
#endif // !defined(CONFIG_IDF_TARGET_ESP32C3) && !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6)
#endif // defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)

View File

@ -159,27 +159,35 @@
static inline __attribute__((always_inline))
IO_REG_TYPE directRead(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6 // max. usable Pins are 23 for C6 (below flash pins)
// return digitalRead(pin); // Works most of the time
// return gpio_ll_get_level(&GPIO, pin); // The hal is not public api, don't use in application code
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
#if SOC_GPIO_PIN_COUNT <= 32
return (GPIO.in.val >> pin) & 0x1;
#else // plain ESP32
#else // ESP32 with over 32 gpios
if ( pin < 32 )
return (GPIO.in >> pin) & 0x1;
else if ( pin < 46 )
else
return (GPIO.in1.val >> (pin - 32)) & 0x1;
#endif
return 0;
}
static inline __attribute__((always_inline))
void directWriteLow(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
// digitalWrite(pin, 0); // Works most of the time
// gpio_ll_set_level(&GPIO, pin, 0); // The hal is not public api, don't use in application code
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
#if SOC_GPIO_PIN_COUNT <= 32
GPIO.out_w1tc.val = ((uint32_t)1 << pin);
#else // plain ESP32
#else // ESP32 with over 32 gpios
if ( pin < 32 )
GPIO.out_w1tc = ((uint32_t)1 << pin);
else if ( pin < 46 )
else
GPIO.out1_w1tc.val = ((uint32_t)1 << (pin - 32));
#endif
}
@ -187,66 +195,63 @@ void directWriteLow(IO_REG_TYPE pin)
static inline __attribute__((always_inline))
void directWriteHigh(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
// digitalWrite(pin, 1); // Works most of the time
// gpio_ll_set_level(&GPIO, pin, 1); // The hal is not public api, don't use in application code
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
#if SOC_GPIO_PIN_COUNT <= 32
GPIO.out_w1ts.val = ((uint32_t)1 << pin);
#else // plain ESP32
#else // ESP32 with over 32 gpios
if ( pin < 32 )
GPIO.out_w1ts = ((uint32_t)1 << pin);
else if ( pin < 46 )
else
GPIO.out1_w1ts.val = ((uint32_t)1 << (pin - 32));
#endif
}
static inline __attribute__((always_inline))
void directModeInput(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
GPIO.enable_w1tc.val = ((uint32_t)1 << (pin));
#else
// pinMode(pin, INPUT); // Too slow - doesn't work
// gpio_ll_output_disable(&GPIO, pin); // The hal is not public api, don't use in application code
if ( digitalPinIsValid(pin) )
{
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
if ( rtc_reg ) // RTC pins PULL settings
{
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
}
#endif
// Input
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
#if SOC_GPIO_PIN_COUNT <= 32
GPIO.enable_w1tc.val = ((uint32_t)1 << (pin));
#else // ESP32 with over 32 gpios
if ( pin < 32 )
GPIO.enable_w1tc = ((uint32_t)1 << pin);
else
GPIO.enable1_w1tc.val = ((uint32_t)1 << (pin - 32));
}
#endif
}
}
static inline __attribute__((always_inline))
void directModeOutput(IO_REG_TYPE pin)
{
#if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C6
GPIO.enable_w1ts.val = ((uint32_t)1 << (pin));
#else
if ( digitalPinIsValid(pin) && pin <= 33 ) // pins above 33 can be only inputs
{
#if ESP_IDF_VERSION_MAJOR < 4 // IDF 3.x ESP32/PICO-D4
uint32_t rtc_reg(rtc_gpio_desc[pin].reg);
// pinMode(pin, OUTPUT); // Too slow - doesn't work
// gpio_ll_output_enable(&GPIO, pin); // The hal is not public api, don't use in application code
if ( rtc_reg ) // RTC pins PULL settings
{
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].mux);
ESP_REG(rtc_reg) = ESP_REG(rtc_reg) & ~(rtc_gpio_desc[pin].pullup | rtc_gpio_desc[pin].pulldown);
}
#endif
if ( digitalPinCanOutput(pin) )
{
// Output
//#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
#if SOC_GPIO_PIN_COUNT <= 32
GPIO.enable_w1ts.val = ((uint32_t)1 << (pin));
#else // ESP32 with over 32 gpios
if ( pin < 32 )
GPIO.enable_w1ts = ((uint32_t)1 << pin);
else // already validated to pins <= 33
else
GPIO.enable1_w1ts.val = ((uint32_t)1 << (pin - 32));
}
#endif
}
}
#define DIRECT_READ(base, pin) directRead(pin)
@ -254,7 +259,6 @@ void directModeOutput(IO_REG_TYPE pin)
#define DIRECT_WRITE_HIGH(base, pin) directWriteHigh(pin)
#define DIRECT_MODE_INPUT(base, pin) directModeInput(pin)
#define DIRECT_MODE_OUTPUT(base, pin) directModeOutput(pin)
//#warning "ESP32 OneWire testing"
#elif defined(__SAMD21G18A__)
#define PIN_TO_BASEREG(pin) portModeRegister(digitalPinToPort(pin))

View File

@ -79,6 +79,11 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
uint8_t *frame;
uint8_t framepointer = 0;
#ifdef TASMOTAMODBUSDEBUG
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: @%02X f:%02X r:%04X c:%u &:%08X"), device_address, function_code, start_address, count, (uint32)write_data);
if (write_data) AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: Write data 0x%04X"), write_data[0]);
#endif
uint16_t byte_count = count * 2; // In register mode count is nr of registers (2 bytes)
if ((function_code == 1) || (function_code == 2) || (function_code == 15)) byte_count = ((count-1) / 8) + 1; // In bitmode count is nr of bits
@ -104,14 +109,20 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
}
else if ((function_code == 5) || (function_code == 6))
{
if (write_data == NULL)
if (write_data == nullptr)
{
free(frame);
#ifdef TASMOTAMODBUSDEBUG
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: no data (13.1)"));
#endif
return 13; // Register data not specified
}
if (count != 1)
{
free(frame);
#ifdef TASMOTAMODBUSDEBUG
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: wrong count (12.1)"));
#endif
return 12; // Wrong register count
}
frame[framepointer++] = (uint8_t)(write_data[0] >> 8); // MSB
@ -124,14 +135,20 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
frame[framepointer++] = byte_count;
if (write_data == NULL)
if (write_data == nullptr)
{
free(frame);
#ifdef TASMOTAMODBUSDEBUG
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: no data (13.2)"));
#endif
return 13; // Register data not specified
}
if (count == 0)
{
free(frame);
#ifdef TASMOTAMODBUSDEBUG
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: wrong count (12.2)"));
#endif
return 12; // Wrong register count
}
for (uint16_t bytepointer = 0; bytepointer < byte_count; bytepointer++)
@ -142,6 +159,9 @@ uint8_t TasmotaModbus::Send(uint8_t device_address, uint8_t function_code, uint1
else
{
free(frame);
#ifdef TASMOTAMODBUSDEBUG
AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("MBS: Serial Send: wrong fct (1)"));
#endif
return 1; // Wrong function code
}

View File

@ -24,12 +24,17 @@
#include "esp8266toEsp32.h"
#endif
#include "tasmota_options.h"
extern int Cache_WriteBack_Addr(uint32_t addr, uint32_t size);
//#define UDSP_DEBUG
#ifndef UDSP_LBSIZE
#define UDSP_LBSIZE 256
#endif
#define renderer_swap(a, b) { int16_t t = a; a = b; b = t; }
const uint16_t udisp_colors[]={UDISP_BLACK,UDISP_WHITE,UDISP_RED,UDISP_GREEN,UDISP_BLUE,UDISP_CYAN,UDISP_MAGENTA,\
@ -133,7 +138,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
}
lut_partial = 0;
lut_full = 0;
char linebuff[128];
char linebuff[UDSP_LBSIZE];
while (*lp) {
uint16_t llen = strlen_ln(lp);
@ -153,10 +158,50 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
lp1++;
section = *lp1++;
if (section == 'I') {
if (*lp1 == 'C') {
allcmd_mode = 1;
lp1++;
}
if (*lp1 == 'S') {
// pecial case RGB with software SPI init clk,mosi,cs,reset
lp1++;
if (interface == _UDSP_RGB) {
// collect line and send directly
lp1++;
spi_nr = 4;
spi_dc = -1;
spi_miso = -1;
spi_clk = next_val(&lp1);
spi_mosi = next_val(&lp1);
spi_cs = next_val(&lp1);
reset = next_val(&lp1);
pinMode(spi_cs, OUTPUT);
digitalWrite(spi_cs, HIGH);
pinMode(spi_clk, OUTPUT);
digitalWrite(spi_clk, LOW);
pinMode(spi_mosi, OUTPUT);
digitalWrite(spi_mosi, LOW);
if (reset >= 0) {
pinMode(reset, OUTPUT);
digitalWrite(reset, HIGH);
delay(50);
reset_pin(50, 200);
}
#ifdef UDSP_DEBUG
Serial.printf("SSPI_MOSI : %d\n", spi_mosi);
Serial.printf("SSPI_SCLK : %d\n", spi_clk);
Serial.printf("SSPI_CS : %d\n", spi_cs);
Serial.printf("DSP RESET : %d\n", reset);
#endif
}
}
} else if (section == 'L') {
if (*lp1 >= '1' && *lp1 <= '5') {
lut_num = (*lp1 & 0x07);
@ -178,8 +223,9 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
lut_cmd[0] = next_hex(&lp1);
}
if (*lp1 == ',') lp1++;
}
if (*lp1 != ':' && *lp1 != '\n' && *lp1 != ' ') { // Add space char
if (*lp1 && *lp1 != ':' && *lp1 != '\n' && *lp1 != ' ') { // Add space char
switch (section) {
case 'H':
// header line
@ -286,12 +332,10 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
break;
case 'I':
// init data
if (interface == _UDSP_I2C) {
dsp_cmds[dsp_ncmds++] = next_hex(&lp1);
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
}
} else {
if (interface == _UDSP_RGB && spi_nr == 4) {
// special case RGB with SPI init
// collect line and send directly
dsp_ncmds = 0;
while (1) {
if (dsp_ncmds >= sizeof(dsp_cmds)) break;
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
@ -300,6 +344,26 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
break;
}
}
interface = _UDSP_SPI;
send_spi_icmds(dsp_ncmds);
interface = _UDSP_RGB;
} else {
if (interface == _UDSP_I2C) {
dsp_cmds[dsp_ncmds++] = next_hex(&lp1);
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
}
} else {
while (1) {
if (dsp_ncmds >= sizeof(dsp_cmds)) break;
if (!str2c(&lp1, ibuff, sizeof(ibuff))) {
dsp_cmds[dsp_ncmds++] = strtol(ibuff, 0, 16);
} else {
break;
}
}
}
}
break;
case 'f':
@ -481,6 +545,7 @@ uDisplay::uDisplay(char *lp) : Renderer(800, 600) {
}
}
}
nextline:
if (*lp == '\n' || *lp == ' ') { // Add space char
lp++;
} else {
@ -648,6 +713,50 @@ void uDisplay::delay_arg(uint32_t args) {
extern int32_t ESP_ResetInfoReason();
// special init for GC displays
void uDisplay::send_spi_icmds(uint16_t cmd_size) {
uint16_t index = 0;
uint16_t cmd_offset = 0;
#ifdef UDSP_DEBUG
Serial.printf("start send icmd table\n");
#endif
while (1) {
uint8_t iob;
SPI_CS_LOW
iob = dsp_cmds[cmd_offset++];
index++;
ulcd_command(iob);
uint8_t args = dsp_cmds[cmd_offset++];
index++;
#ifdef UDSP_DEBUG
Serial.printf("cmd, args %02x, %d ", iob, args & 0x7f);
#endif
for (uint32_t cnt = 0; cnt < (args & 0x7f); cnt++) {
iob = dsp_cmds[cmd_offset++];
index++;
#ifdef UDSP_DEBUG
Serial.printf("%02x ", iob);
#endif
ulcd_data8(iob);
}
SPI_CS_HIGH
#ifdef UDSP_DEBUG
Serial.printf("\n");
#endif
if (args & 0x80) { // delay after the command
delay_arg(args);
}
if (index >= cmd_size) break;
}
#ifdef UDSP_DEBUG
Serial.printf("end send icmd table\n");
#endif
return;
}
void uDisplay::send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size) {
uint16_t index = 0;
#ifdef UDSP_DEBUG
@ -945,7 +1054,11 @@ Renderer *uDisplay::Init(void) {
_panel_config->disp_gpio_num = GPIO_NUM_NC;
_panel_config->flags.disp_active_low = 0;
#if ESP_IDF_VERSION_MAJOR >= 5
_panel_config->flags.refresh_on_demand = 0;
#else
_panel_config->flags.relax_on_idle = 0;
#endif // ESP_IDF_VERSION_MAJOR >= 5
_panel_config->flags.fb_in_psram = 1; // allocate frame buffer in PSRAM
ESP_ERROR_CHECK(esp_lcd_new_rgb_panel(_panel_config, &_panel_handle));
@ -955,9 +1068,16 @@ Renderer *uDisplay::Init(void) {
uint16_t color = random(0xffff);
ESP_ERROR_CHECK(_panel_handle->draw_bitmap(_panel_handle, 0, 0, 1, 1, &color));
#if ESP_IDF_VERSION_MAJOR < 5
_rgb_panel = __containerof(_panel_handle, esp_rgb_panel_t, base);
rgb_fb = (uint16_t *)_rgb_panel->fb;
#else
void * buf = NULL;
esp_lcd_rgb_panel_get_frame_buffer(_panel_handle, 1, &buf);
rgb_fb = (uint16_t *)buf;
#endif
#endif // USE_ESP32_S3
}
@ -1032,12 +1152,14 @@ Renderer *uDisplay::Init(void) {
esp_lcd_new_i80_bus(&bus_config, &_i80_bus);
#if ESP_IDF_VERSION_MAJOR < 5
_dma_chan = _i80_bus->dma_chan;
#endif
uint32_t div_a, div_b, div_n, clkcnt;
calcClockDiv(&div_a, &div_b, &div_n, &clkcnt, 240*1000*1000, spi_speed*1000000);
lcd_cam_lcd_clock_reg_t lcd_clock;
lcd_clock.lcd_clkcnt_n = std::max(1u, clkcnt - 1);
lcd_clock.lcd_clkcnt_n = std::max((uint32_t)1u, clkcnt - 1); // ESP_IDF_VERSION_MAJOR >= 5
lcd_clock.lcd_clk_equ_sysclk = (clkcnt == 1);
lcd_clock.lcd_ck_idle_edge = true;
lcd_clock.lcd_ck_out_edge = false;
@ -2406,6 +2528,7 @@ void uDisplay::hw_write9(uint8_t val, uint8_t dc) {
*dp = regvalue;
REG_SET_BIT(SPI_CMD_REG(3), SPI_USR);
while (REG_GET_FIELD(SPI_CMD_REG(3), SPI_USR));
}
#else

View File

@ -6,15 +6,15 @@
#include <Wire.h>
#include <SPI.h>
#ifdef ESP32
#ifdef CONFIG_IDF_TARGET_ESP32S3
#define USE_ESP32_S3
#endif
#endif
#ifdef ESP32
#include "driver/spi_master.h"
#if ESP_IDF_VERSION_MAJOR >= 5
#include "soc/gpio_periph.h"
#include <rom/gpio.h>
#endif // ESP_IDF_VERSION_MAJOR >= 5
#endif
#ifdef USE_ESP32_S3
@ -37,6 +37,9 @@ static inline void gpio_lo(int_fast8_t pin) { if (pin >= 0) *get_gpio_lo_reg(pin
#include "esp_lcd_panel_ops.h"
#include <hal/dma_types.h>
#include <rom/cache.h>
#if ESP_IDF_VERSION_MAJOR >= 5
#include "esp_rom_lldesc.h"
#endif // ESP_IDF_VERSION_MAJOR >= 5
#endif // USE_ESP32_S3
#define _UDSP_I2C 1
@ -89,13 +92,16 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
#undef GPIO_CLR
#undef GPIO_SET_SLOW
#undef GPIO_CLR_SLOW
#if CONFIG_IDF_TARGET_ESP32C3
#if CONFIG_IDF_TARGET_ESP32C2 || CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32C6
#define GPIO_CLR(A) GPIO.out_w1tc.val = (1 << A)
#define GPIO_SET(A) GPIO.out_w1ts.val = (1 << A)
#else // plain ESP32
#define GPIO_CLR(A) GPIO.out_w1tc = (1 << A)
#define GPIO_SET(A) GPIO.out_w1ts = (1 << A)
#endif
#define GPIO_CLR_SLOW(A) digitalWrite(A, LOW)
#define GPIO_SET_SLOW(A) digitalWrite(A, HIGH)
@ -110,7 +116,7 @@ enum uColorType { uCOLOR_BW, uCOLOR_COLOR };
#define SPI_DC_HIGH if (spi_dc >= 0) GPIO_SET_SLOW(spi_dc);
#ifdef USE_ESP32_S3
#if defined(USE_ESP32_S3) && ESP_IDF_VERSION_MAJOR < 5
struct esp_lcd_i80_bus_t {
int bus_id; // Bus ID, index from 0
portMUX_TYPE spinlock; // spinlock used to protect i80 bus members(hal, device_list, cur_trans)
@ -143,7 +149,9 @@ struct esp_rgb_panel_t
size_t resolution_hz; // Peripheral clock resolution
esp_lcd_rgb_timing_t timings; // RGB timing parameters (e.g. pclk, sync pulse, porch width)
gdma_channel_handle_t dma_chan; // DMA channel handle
#if ESP_IDF_VERSION_MAJOR < 5
esp_lcd_rgb_panel_frame_trans_done_cb_t on_frame_trans_done; // Callback, invoked after frame trans done
#endif // ESP_IDF_VERSION_MAJOR < 5
void *user_ctx; // Reserved user's data of callback functions
int x_gap; // Extra gap in x coordinate, it's used when calculate the flush window
int y_gap; // Extra gap in y coordinate, it's used when calculate the flush window
@ -155,8 +163,7 @@ struct esp_rgb_panel_t
} flags;
dma_descriptor_t dma_nodes[]; // DMA descriptor pool of size `num_dma_nodes`
};
#endif
#endif //USE_ESP32_S3 && ESP_IDF_VERSION_MAJOR < 5
class uDisplay : public Renderer {
@ -326,6 +333,8 @@ class uDisplay : public Renderer {
void delay_arg(uint32_t arg);
void Send_EP_Data(void);
void send_spi_cmds(uint16_t cmd_offset, uint16_t cmd_size);
void send_spi_icmds(uint16_t cmd_size);
#ifdef USE_ESP32_S3
int8_t par_cs;
@ -352,7 +361,9 @@ class uDisplay : public Renderer {
uint16_t pclk_active_neg;
esp_lcd_panel_handle_t _panel_handle = NULL;
#if ESP_IDF_VERSION_MAJOR < 5
esp_rgb_panel_t *_rgb_panel;
#endif //ESP_IDF_VERSION_MAJOR < 5
uint16_t *rgb_fb;

View File

@ -821,7 +821,7 @@ MFRC522::StatusCode MFRC522Extended::TCL_Transceive(TagInfo *tag, byte *sendData
// Swap block number on success
tag->blockNumber = !tag->blockNumber;
if (backData && (backLen > 0)) {
if (backData && (backLen != 0)) {
if (*backLen < in.inf.size)
return STATUS_NO_ROOM;
@ -844,7 +844,7 @@ MFRC522::StatusCode MFRC522Extended::TCL_Transceive(TagInfo *tag, byte *sendData
if (result != STATUS_OK)
return result;
if (backData && (backLen > 0)) {
if (backData && (backLen != 0)) {
if ((*backLen + ackDataSize) > totalBackLen)
return STATUS_NO_ROOM;

View File

@ -214,7 +214,7 @@ void Adafruit_TSL2591::setGain(tsl2591Gain_t gain)
enable();
_gain = gain;
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, static_cast<uint8_t>(_integration) | static_cast<uint8_t>(_gain));
disable();
}
@ -245,7 +245,7 @@ void Adafruit_TSL2591::setTiming(tsl2591IntegrationTime_t integration)
enable();
_integration = integration;
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, _integration | _gain);
write8(TSL2591_COMMAND_BIT | TSL2591_REGISTER_CONTROL, static_cast<uint8_t>(_integration) | static_cast<uint8_t>(_gain));
disable();
}

View File

@ -47,7 +47,7 @@ bool Tsl2561::begin() {
bool Tsl2561::readByte( register_t reg, uint8_t &val ) {
_wire.beginTransmission(_addr);
_wire.write(reg | CONTROL_CMD);
_wire.write(reg | static_cast<uint8_t>(CONTROL_CMD));
if( (_status = static_cast<status_t>(_wire.endTransmission(false))) == ERR_OK ) {
if( _wire.requestFrom(_addr, 1) == 1 ) {
val = static_cast<uint8_t>(_wire.read());
@ -61,7 +61,7 @@ bool Tsl2561::readByte( register_t reg, uint8_t &val ) {
bool Tsl2561::readWord( register_t reg, uint16_t &val ) {
_wire.beginTransmission(_addr);
_wire.write(reg | CONTROL_CMD);
_wire.write(reg | static_cast<uint8_t>(CONTROL_CMD));
if( (_status = static_cast<status_t>(_wire.endTransmission(false))) == ERR_OK ) {
if( _wire.requestFrom(_addr, 2) == 2 ) {
val = static_cast<uint16_t>(_wire.read()) & 0xff;
@ -76,7 +76,7 @@ bool Tsl2561::readWord( register_t reg, uint16_t &val ) {
bool Tsl2561::writeByte( register_t reg, uint8_t val ) {
_wire.beginTransmission(_addr);
_wire.write(reg | CONTROL_CMD);
_wire.write(reg | static_cast<uint8_t>(CONTROL_CMD));
_wire.write(val);
return (_status = static_cast<status_t>(_wire.endTransmission())) == ERR_OK;
}
@ -118,7 +118,7 @@ bool Tsl2561::off() {
}
bool Tsl2561::setSensitivity( bool gain, exposure_t exposure ) {
return writeByte(REG_TIMING, (gain ? GAIN_ON : GAIN_OFF) | exposure);
return writeByte(REG_TIMING, (gain ? GAIN_ON : GAIN_OFF) | static_cast<uint8_t>(exposure));
}
bool Tsl2561::getSensitivity( bool &gain, exposure_t &exposure )

View File

@ -42,7 +42,7 @@ public:
ADDR_VDD = 0b1001001
} address_t;
typedef enum {
typedef enum : uint8_t {
REG_CONTROL, // Control of basic functions
REG_TIMING, // Integration time/gain control
REG_THRESHLOWLOW, // Low byte of low interrupt threshold
@ -61,7 +61,7 @@ public:
REG_DATA1HIGH // High byte of ADC channel 1
} register_t;
enum {
enum : uint8_t{
CONTROL_CMD = 0b10000000,
CONTROL_CLEAR = 0b01000000,
CONTROL_WORD = 0b00100000, // SPI only?

View File

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2021 mobizt
Copyright (c) 2020 Sciosense
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

View File

@ -0,0 +1,38 @@
# ScioSense ENS16x
Arduino library for the ENS160 and ENS161 digital four channel MOX gas sensor with I2C interface from ScioSense
## Introduction
This project is an Arduino *library*. It implements a driver with examples for the ENS160 and ENS161.
The ENS16x chip is a digital gas sensor for TVOC and eCO2 with an I2C interface.
The driver in this Arduino library is based on the code supplied by *Sciosense*, the manufacturer of the chip.
Note that the ENS16x requires a supply voltage of 1.71V .. 1.98V.
The ENS16x also requires a IO voltage of 1.71V .. 3.6V.
## Links
The ENS16x is made by [Sciosense](http://www.sciosense.com).
- The datasheet of the ENS160 is available through the website. The datasheet of ENS161 is not yet released but can be provided on request
## Prerequisites
It is assumed that
- The Arduino IDE has been installed.
If not, refer to "Install the Arduino Desktop IDE" on the
[Arduino site](https://www.arduino.cc/en/Guide/HomePage).
- The library directory is at its default location.
For me, that is `C:\Users\sciosense\Documents\Arduino\libraries`.
## Installation
- Visit the project page for the Arduino ENS16x library.
- Click the green button Clone or download on the right side.
- From the pop-up choose Download ZIP.
- In Arduino IDE, select Sketch > Include Library > Manage Libraries ... and browse to the just downloaded ZIP file.
- When the IDE is ready this README.md should be located at e.g. `C:\Users\sciosense\Documents\Arduino\libraries\ScioSense_ENS16x\README.md`.
## Build an example
To build an example sketch
- (Re)start Arduino.
- Open File > Example > Examples from Custom Libraries > ENS16x > ENS16xbasic_normal
- Make sure Tools > Board lists the correct board.
- Select Sketch > Verify/Compile.
### ScioSense is a Joint Venture of ams AG

View File

@ -0,0 +1,65 @@
#######################################
# Syntax Coloring Map
#######################################
# https://spencer.bliven.us/index.php/2012/01/18/arduino-ide-keywords/
# KEYWORD1 Classes, datatypes, and C++ keywords
# KEYWORD2 Methods and functions
# KEYWORD3 setup and loop functions, as well as the Serial keywords
# LITERAL1 Constants
# LITERAL2 Built-in variables (unused by default)
#######################################
# Classes, datatypes (KEYWORD1)
#######################################
ENS160 KEYWORD1
ens160 KEYWORD1
ENS161 KEYWORD1
ens161 KEYWORD1
ScioSense_ENS16x KEYWORD1
ScioSense_ens16x KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
setI2C KEYWORD2
available KEYWORD2
revENS16x KEYWORD2
setMode KEYWORD2
initCustomMode KEYWORD2
addCustomStep KEYWORD2
measure KEYWORD2
measureRaw KEYWORD2
set_envdata KEYWORD2
set_envdata210 KEYWORD2
getMajorRev KEYWORD2
getMinorRev KEYWORD2
getBuild KEYWORD2
getAQI KEYWORD2
getTVOC KEYWORD2
geteCO2 KEYWORD2
getAQIS KEYWORD2
getHP0 KEYWORD2
getHP0BL KEYWORD2
getHP1 KEYWORD2
getHP1BL KEYWORD2
getHP2 KEYWORD2
getHP2BL KEYWORD2
getHP3 KEYWORD2
getHP3BL KEYWORD2
getMISR KEYWORD2
######################################
# Constants (LITERAL1)
#######################################
ENS16x_I2CADDR_0 LITERAL1
ENS16x_I2CADDR_1 LITERAL1
ENS16x_OPMODE_IDLE LITERAL1
ENS16x_OPMODE_STD LITERAL1
ENS161_OPMODE_LP LITERAL1
ENS16x_OPMODE_CUSTOM LITERAL1

View File

@ -0,0 +1,9 @@
name=ScioSense ENS16x
version=8.0.0
author=Christoph Friese
maintainer=ScioSense
sentence=Arduino library for the ENS160 and ENS161 digital four channel MOX gas sensor with I2C interface from ScioSense
paragraph=This library controls the ENS160 and ENS161. The main feature of this library is performing a single shot measurement, retrieving the measurement data.
category=Device Control
url=https://github.com/sciosense/ens16x
architectures=*

View File

@ -0,0 +1,490 @@
/*
ScioSense_ENS16x.h - Library for the ENS160 & ENS161 sensor with I2C interface from ScioSense
2023 Jul 03 v8 Christoph Friese Update to cover ENS160 and ENS161
2023 Mar 23 v7 Christoph Friese Bugfix measurement routine, prepare next release
2021 Nov 25 v6 Martin Herold Custom mode timing fixed
2021 July 29 v5 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams
2021 Feb 04 v4 Giuseppe de Pinto Custom mode fixed
2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams
2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option
2019 May 05 v1 Christoph Friese Created
based on application note "ENS160 Software Integration.pdf" rev 0.01
*/
#include "ScioSense_ENS16x.h"
#include "math.h"
ScioSense_ENS16x::ScioSense_ENS16x(uint8_t slaveaddr) {
this->_slaveaddr = slaveaddr;
this->_ADDR = 0;
this->_nINT = 0;
this->_nCS = 0;
}
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
ScioSense_ENS16x::ScioSense_ENS16x(uint8_t ADDR, uint8_t nCS, uint8_t nINT) {
this->_slaveaddr = ENS16x_I2CADDR_0;
this->_ADDR = ADDR;
this->_nINT = nINT;
this->_nCS = nCS;
}
ScioSense_ENS16x::ScioSense_ENS16x(uint8_t slaveaddr, uint8_t ADDR, uint8_t nCS, uint8_t nINT) {
this->_slaveaddr = slaveaddr;
this->_ADDR = ADDR;
this->_nINT = nINT;
this->_nCS = nCS;
}
// Function to redefine I2C pins
void ScioSense_ENS16x::setI2C(uint8_t sda, uint8_t scl) {
this->_sdaPin = sda;
this->_sclPin = scl;
}
#endif
// Init I2C communication, resets ENS16x and checks its PART_ID. Returns false on I2C problems or wrong PART_ID.
bool ScioSense_ENS16x::begin(bool debug)
{
#ifndef ENS16x_DISABLE_DEBUG
debugENS16x = debug;
//Set pin levels
if (this->_ADDR > 0) {
pinMode(this->_ADDR, OUTPUT);
digitalWrite(this->_ADDR, LOW);
}
if (this->_nINT > 0) pinMode(this->_nINT, INPUT_PULLUP);
if (this->_nCS > 0) {
pinMode(this->_nCS, OUTPUT);
digitalWrite(this->_nCS, HIGH);
}
#endif
//init I2C
_i2c_init();
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.println("begin() - I2C init done");
}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
this->_available = false;
this->_available = this->reset();
this->_available = this->checkPartID();
if (this->_available) {
this->_available = this->setMode(ENS16x_OPMODE_IDLE);
this->_available = this->clearCommand();
this->_available = this->getFirmware();
}
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.println("ENS16x in idle mode");
}
#endif
return this->_available;
}
// Sends a reset to the ENS16x. Returns false on I2C problems.
bool ScioSense_ENS16x::reset(void)
{
uint8_t result = this->write8(_slaveaddr, ENS16x_REG_OPMODE, ENS16x_OPMODE_RESET);
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("reset() result: ");
Serial.println(result == 0 ? "ok" : "nok");
}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
return result == 0;
}
// Reads the part ID and confirms valid sensor
bool ScioSense_ENS16x::checkPartID(void) {
uint8_t i2cbuf[2];
uint16_t part_id;
bool result = false;
this->read(_slaveaddr, ENS16x_REG_PART_ID, i2cbuf, 2);
part_id = i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8);
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("checkPartID() result: ");
if (part_id == ENS160_PARTID) Serial.println("ENS160 ok");
else if (part_id == ENS161_PARTID) Serial.println("ENS161 ok");
else Serial.println("nok");
}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
if (part_id == ENS160_PARTID) { this->_revENS16x = 0; result = true; }
else if (part_id == ENS161_PARTID) { this->_revENS16x = 1; result = true; }
return result;
}
// Initialize idle mode and confirms
bool ScioSense_ENS16x::clearCommand(void) {
uint8_t status;
uint8_t result;
result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_NOP);
result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_CLRGPR);
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("clearCommand() result: ");
Serial.println(result == 0 ? "ok" : "nok");
}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS);
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("clearCommand() status: 0x");
Serial.println(status, HEX);
}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
return result == 0;
}
// Read firmware revisions
bool ScioSense_ENS16x::getFirmware() {
uint8_t i2cbuf[3];
uint8_t result;
this->clearCommand();
delay(ENS16x_BOOTING); // Wait to boot after reset
result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_GET_APPVER);
result = this->read(_slaveaddr, ENS16x_REG_GPR_READ_4, i2cbuf, 3);
this->_fw_ver_major = i2cbuf[0];
this->_fw_ver_minor = i2cbuf[1];
this->_fw_ver_build = i2cbuf[2];
if (this->_fw_ver_major > 6) this->_revENS16x = 1;
else this->_revENS16x = 0;
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.println(this->_fw_ver_major);
Serial.println(this->_fw_ver_minor);
Serial.println(this->_fw_ver_build);
Serial.print("getFirmware() result: ");
Serial.println(result == 0 ? "ok" : "nok");
}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
return result == 0;
}
// Set operation mode of sensor
bool ScioSense_ENS16x::setMode(uint8_t mode) {
uint8_t result;
//LP only valid for rev>0
if ((mode == ENS161_OPMODE_LP) and (_revENS16x == 0)) result = 1;
else result = this->write8(_slaveaddr, ENS16x_REG_OPMODE, mode);
#ifndef ENS16x_DISABLE_DEBUG
//if (debugENS16x) {
Serial.print("setMode() activate result: ");
Serial.println(result == 0 ? "ok" : "nok");
//}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
return result == 0;
}
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
// Initialize definition of custom mode with <n> steps
bool ScioSense_ENS16x::initCustomMode(uint16_t stepNum) {
uint8_t result;
if (stepNum > 0) {
this->_stepCount = stepNum;
result = this->setMode(ENS16x_OPMODE_IDLE);
result = this->clearCommand();
result = this->write8(_slaveaddr, ENS16x_REG_COMMAND, ENS16x_COMMAND_SETSEQ);
} else {
result = 1;
}
delay(ENS16x_BOOTING); // Wait to boot after reset
return result == 0;
}
#endif
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
// Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate
bool ScioSense_ENS16x::addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3) {
uint8_t seq_ack;
uint8_t temp;
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("setCustomMode() write step ");
Serial.println(this->_stepCount);
}
#endif
delay(ENS16x_BOOTING); // Wait to boot after reset
temp = (uint8_t)(((time / 24)-1) << 6);
if (measureHP0) temp = temp | 0x20;
if (measureHP1) temp = temp | 0x10;
if (measureHP2) temp = temp | 0x8;
if (measureHP3) temp = temp | 0x4;
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_0, temp);
temp = (uint8_t)(((time / 24)-1) >> 2);
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_1, temp);
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_2, (uint8_t)(tempHP0/2));
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_3, (uint8_t)(tempHP1/2));
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_4, (uint8_t)(tempHP2/2));
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_5, (uint8_t)(tempHP3/2));
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_6, (uint8_t)(this->_stepCount - 1));
if (this->_stepCount == 1) {
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_7, 128);
} else {
this->write8(_slaveaddr, ENS16x_REG_GPR_WRITE_7, 0);
}
delay(ENS16x_BOOTING);
seq_ack = this->read8(_slaveaddr, ENS16x_REG_GPR_READ_7);
delay(ENS16x_BOOTING); // Wait to boot after reset
if ((ENS16x_SEQ_ACK_COMPLETE | this->_stepCount) != seq_ack) {
this->_stepCount = this->_stepCount - 1;
return 0;
} else {
return 1;
}
}
#endif
// Perform prediction measurement and stores result in internal variables
bool ScioSense_ENS16x::measure(bool waitForNew) {
uint8_t i2cbuf[8];
uint8_t status;
bool newData = false;
// Set default status for early bail out
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) Serial.println("Start measurement");
#endif
if (waitForNew) {
do {
delay(10);
status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS);
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("Status: ");
Serial.println(status);
}
#endif
} while (!IS_NEWDAT(status));
} else {
status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS);
}
// Read predictions
if (IS_NEWDAT(status)) {
newData = true;
this->read(_slaveaddr, ENS16x_REG_DATA_AQI, i2cbuf, 7);
_data_aqi = i2cbuf[0];
_data_tvoc = i2cbuf[1] | ((uint16_t)i2cbuf[2] << 8);
_data_eco2 = i2cbuf[3] | ((uint16_t)i2cbuf[4] << 8);
if (_revENS16x > 0) _data_aqis = ((uint16_t)i2cbuf[5]) | ((uint16_t)i2cbuf[6] << 8);
else _data_aqis = 0;
}
return newData;
}
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
// Perfrom raw measurement and stores result in internal variables
bool ScioSense_ENS16x::measureRaw(bool waitForNew) {
uint8_t i2cbuf[8];
uint8_t status;
bool newData = false;
// Set default status for early bail out
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) Serial.println("Start measurement");
#endif
if (waitForNew) {
do {
delay(10);
status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS);
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("Status: ");
Serial.println(status);
}
#endif
} while (!IS_NEWGPR(status));
} else {
status = this->read8(_slaveaddr, ENS16x_REG_DATA_STATUS);
}
if (IS_NEWGPR(status)) {
newData = true;
// Read raw resistance values
this->read(_slaveaddr, ENS16x_REG_GPR_READ_0, i2cbuf, 8);
_hp0_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8)));
_hp1_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8)));
_hp2_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8)));
_hp3_rs = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8)));
// Read baselines
this->read(_slaveaddr, ENS16x_REG_DATA_BL, i2cbuf, 8);
_hp0_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[0] | ((uint16_t)i2cbuf[1] << 8)));
_hp1_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[2] | ((uint16_t)i2cbuf[3] << 8)));
_hp2_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[4] | ((uint16_t)i2cbuf[5] << 8)));
_hp3_bl = CONVERT_RS_RAW2OHMS_F((uint32_t)(i2cbuf[6] | ((uint16_t)i2cbuf[7] << 8)));
this->read(_slaveaddr, ENS16x_REG_DATA_MISR, i2cbuf, 1);
_misr = i2cbuf[0];
}
return newData;
}
// Writes t (degC) and h (%rh) to ENV_DATA. Returns false on I2C problems.
bool ScioSense_ENS16x::set_envdata(float t, float h) {
uint16_t t_data = (uint16_t)((t + 273.15f) * 64.0f);
uint16_t rh_data = (uint16_t)(h * 512.0f);
return this->set_envdata210(t_data, rh_data);
}
// Writes t and h (in ENS210 format) to ENV_DATA. Returns false on I2C problems.
bool ScioSense_ENS16x::set_envdata210(uint16_t t, uint16_t h) {
//uint16_t temp;
uint8_t trh_in[4];
//temp = (uint16_t)((t + 273.15f) * 64.0f);
trh_in[0] = t & 0xff;
trh_in[1] = (t >> 8) & 0xff;
//temp = (uint16_t)(h * 512.0f);
trh_in[2] = h & 0xff;
trh_in[3] = (h >> 8) & 0xff;
uint8_t result = this->write(_slaveaddr, ENS16x_REG_TEMP_IN, trh_in, 4);
return result;
}
#endif
/**************************************************************************/
void ScioSense_ENS16x::_i2c_init() {
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
if (this->_sdaPin != this->_sclPin)
Wire.begin(this->_sdaPin, this->_sclPin);
else
#endif
Wire.begin();
}
/**************************************************************************/
uint8_t ScioSense_ENS16x::read8(uint8_t addr, byte reg) {
uint8_t ret;
this->read(addr, reg, &ret, 1);
return ret;
}
uint8_t ScioSense_ENS16x::read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num) {
uint8_t pos = 0;
uint8_t result = 0;
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("I2C read address: 0x");
Serial.print(addr, HEX);
Serial.print(" - register: 0x");
Serial.println(reg, HEX);
}
#endif
//on arduino we need to read in 32 byte chunks
while(pos < num){
uint8_t read_now = min((uint8_t)32, (uint8_t)(num - pos));
Wire.beginTransmission((uint8_t)addr);
Wire.write((uint8_t)reg + pos);
result = Wire.endTransmission();
Wire.requestFrom((uint8_t)addr, read_now);
for(int i=0; i<read_now; i++){
buf[pos] = Wire.read();
pos++;
}
}
return result;
}
/**************************************************************************/
uint8_t ScioSense_ENS16x::write8(uint8_t addr, byte reg, byte value) {
uint8_t result = this->write(addr, reg, &value, 1);
return result;
}
uint8_t ScioSense_ENS16x::write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num) {
#ifndef ENS16x_DISABLE_DEBUG
if (debugENS16x) {
Serial.print("I2C write address: 0x");
Serial.print(addr, HEX);
Serial.print(" - register: 0x");
Serial.print(reg, HEX);
Serial.print(" - value:");
for (int i = 0; i<num; i++) {
Serial.print(" 0x");
Serial.print(buf[i], HEX);
}
Serial.println();
}
#endif
Wire.beginTransmission((uint8_t)addr);
Wire.write((uint8_t)reg);
Wire.write((uint8_t *)buf, num);
uint8_t result = Wire.endTransmission();
return result;
}
/**************************************************************************/

View File

@ -0,0 +1,212 @@
/*
ScioSense_ENS16x.h - Library for the ENS160 & ENS161 sensor with I2C interface from ScioSense
2023 Jul 03 v8 Christoph Friese Update to cover ENS160 and ENS161
2023 Mar 23 v7 Christoph Friese Bugfix measurement routine, prepare next release
2021 Nov 25 v6 Martin Herold Custom mode timing fixed
2021 July 29 v5 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams
2021 Feb 04 v4 Giuseppe de Pinto Custom mode fixed
2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams
2020 Feb 15 v2 Giuseppe Pasetti Corrected firmware flash option
2019 May 05 v1 Christoph Friese Created
based on application note "ENS160 Software Integration.pdf" rev 0.01
*/
#ifndef __SCIOSENSE_ENS16x_H_
#define __SCIOSENSE_ENS16x_H_
#define ENS16x_DISABLE_DEBUG
#define ENS16x_DISABLE_ENHANCED_FEATURES
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
// Chip constants
#define ENS160_PARTID 0x0160
#define ENS161_PARTID 0x0161
#define ENS16x_BOOTING 10
// 7-bit I2C slave address of the ENS16x
#define ENS16x_I2CADDR_0 0x52 //ADDR low
#define ENS16x_I2CADDR_1 0x53 //ADDR high
// ENS16x registers for version V0
#define ENS16x_REG_PART_ID 0x00 // 2 byte register
#define ENS16x_REG_OPMODE 0x10
#define ENS16x_REG_CONFIG 0x11
#define ENS16x_REG_COMMAND 0x12
#define ENS16x_REG_TEMP_IN 0x13
#define ENS16x_REG_RH_IN 0x15
#define ENS16x_REG_DATA_STATUS 0x20
#define ENS16x_REG_DATA_AQI 0x21
#define ENS16x_REG_DATA_TVOC 0x22
#define ENS16x_REG_DATA_ECO2 0x24
#define ENS16x_REG_DATA_BL 0x28
#define ENS16x_REG_DATA_T 0x30
#define ENS16x_REG_DATA_RH 0x32
#define ENS16x_REG_DATA_MISR 0x38
#define ENS16x_REG_GPR_WRITE_0 0x40
#define ENS16x_REG_GPR_WRITE_1 ENS16x_REG_GPR_WRITE_0 + 1
#define ENS16x_REG_GPR_WRITE_2 ENS16x_REG_GPR_WRITE_0 + 2
#define ENS16x_REG_GPR_WRITE_3 ENS16x_REG_GPR_WRITE_0 + 3
#define ENS16x_REG_GPR_WRITE_4 ENS16x_REG_GPR_WRITE_0 + 4
#define ENS16x_REG_GPR_WRITE_5 ENS16x_REG_GPR_WRITE_0 + 5
#define ENS16x_REG_GPR_WRITE_6 ENS16x_REG_GPR_WRITE_0 + 6
#define ENS16x_REG_GPR_WRITE_7 ENS16x_REG_GPR_WRITE_0 + 7
#define ENS16x_REG_GPR_READ_0 0x48
#define ENS16x_REG_GPR_READ_4 ENS16x_REG_GPR_READ_0 + 4
#define ENS16x_REG_GPR_READ_6 ENS16x_REG_GPR_READ_0 + 6
#define ENS16x_REG_GPR_READ_7 ENS16x_REG_GPR_READ_0 + 7
//ENS16x data register fields
#define ENS16x_COMMAND_NOP 0x00
#define ENS16x_COMMAND_CLRGPR 0xCC
#define ENS16x_COMMAND_GET_APPVER 0x0E
#define ENS16x_COMMAND_SETTH 0x02
#define ENS16x_COMMAND_SETSEQ 0xC2
#define ENS16x_OPMODE_RESET 0xF0
#define ENS16x_OPMODE_DEP_SLEEP 0x00
#define ENS16x_OPMODE_IDLE 0x01
#define ENS16x_OPMODE_STD 0x02
#define ENS161_OPMODE_LP 0x03
#define ENS16x_OPMODE_CUSTOM 0xC0
#define ENS16x_BL_CMD_START 0x02
#define ENS16x_BL_CMD_ERASE_APP 0x04
#define ENS16x_BL_CMD_ERASE_BLINE 0x06
#define ENS16x_BL_CMD_WRITE 0x08
#define ENS16x_BL_CMD_VERIFY 0x0A
#define ENS16x_BL_CMD_GET_BLVER 0x0C
#define ENS16x_BL_CMD_GET_APPVER 0x0E
#define ENS16x_BL_CMD_EXITBL 0x12
#define ENS16x_SEQ_ACK_NOTCOMPLETE 0x80
#define ENS16x_SEQ_ACK_COMPLETE 0xC0
#define IS_ENS16x_SEQ_ACK_NOT_COMPLETE(x) (ENS16x_SEQ_ACK_NOTCOMPLETE == (ENS16x_SEQ_ACK_NOTCOMPLETE & (x)))
#define IS_ENS16x_SEQ_ACK_COMPLETE(x) (ENS16x_SEQ_ACK_COMPLETE == (ENS16x_SEQ_ACK_COMPLETE & (x)))
#define ENS16x_DATA_STATUS_NEWDAT 0x02
#define ENS16x_DATA_STATUS_NEWGPR 0x01
#define IS_NEWDAT(x) (ENS16x_DATA_STATUS_NEWDAT == (ENS16x_DATA_STATUS_NEWDAT & (x)))
#define IS_NEWGPR(x) (ENS16x_DATA_STATUS_NEWGPR == (ENS16x_DATA_STATUS_NEWGPR & (x)))
#define IS_NEW_DATA_AVAILABLE(x) (0 != ((ENS16x_DATA_STATUS_NEWDAT | ENS16x_DATA_STATUS_NEWGPR ) & (x)))
#define CONVERT_RS_RAW2OHMS_I(x) (1 << ((x) >> 11))
#define CONVERT_RS_RAW2OHMS_F(x) (pow (2, (float)(x) / 2048))
class ScioSense_ENS16x {
public:
ScioSense_ENS16x(uint8_t slaveaddr = ENS16x_I2CADDR_0); // Constructor using slave address (5A or 5B)
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
ScioSense_ENS16x(uint8_t ADDR, uint8_t nCS, uint8_t nINT); // Constructor with pin definition
ScioSense_ENS16x(uint8_t slaveaddr, uint8_t ADDR, uint8_t nCS, uint8_t nINT); // Constructor with slave address and pin definition
#endif
void setI2C(uint8_t sda, uint8_t scl); // Function to redefine I2C pins
bool begin(bool debug=false); // Init I2C communication, resets ENS16x and checks its PART_ID. Returns false on I2C problems or wrong PART_ID.
bool available() { return this->_available; } // Report availability of sensor
uint8_t revENS16x() { return this->_revENS16x; } // Report version of sensor (0: ENS16x, 1: ENS161)
bool setMode(uint8_t mode); // Set operation mode of sensor
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
bool initCustomMode(uint16_t stepNum); // Initialize definition of custom mode with <n> steps
bool addCustomStep(uint16_t time, bool measureHP0, bool measureHP1, bool measureHP2, bool measureHP3, uint16_t tempHP0, uint16_t tempHP1, uint16_t tempHP2, uint16_t tempHP3);
// Add a step to custom measurement profile with definition of duration, enabled data acquisition and temperature for each hotplate
#endif
bool measure(bool waitForNew = true); // Perform measurement and stores result in internal variables
#ifndef ENS16x_DISABLE_ENHANCED_FEATURES
bool measureRaw(bool waitForNew = true); // Perform raw measurement and stores result in internal variables
bool set_envdata(float t, float h); // Writes t (degC) and h (%rh) to ENV_DATA. Returns "0" if I2C transmission is successful
bool set_envdata210(uint16_t t, uint16_t h); // Writes t and h (in ENS210 format) to ENV_DATA. Returns "0" if I2C transmission is successful
#endif
uint8_t getMajorRev() { return this->_fw_ver_major; } // Get major revision number of used firmware
uint8_t getMinorRev() { return this->_fw_ver_minor; } // Get minor revision number of used firmware
uint8_t getBuild() { return this->_fw_ver_build; } // Get build revision number of used firmware
uint8_t getAQI() { return this->_data_aqi; } // Get AQI value of last measurement
uint16_t getTVOC() { return this->_data_tvoc; } // Get TVOC value of last measurement
uint16_t geteCO2() { return this->_data_eco2; } // Get eCO2 value of last measurement
uint16_t getAQIS() { return this->_data_aqis; } // Get AQI500 value of last measurement
uint32_t getHP0() { return this->_hp0_rs; } // Get resistance of HP0 of last measurement
uint32_t getHP1() { return this->_hp1_rs; } // Get resistance of HP1 of last measurement
uint32_t getHP2() { return this->_hp2_rs; } // Get resistance of HP2 of last measurement
uint32_t getHP3() { return this->_hp3_rs; } // Get resistance of HP3 of last measurement
uint32_t getHP0BL() { return this->_hp0_bl; } // Get baseline resistance of HP0 of last measurement
uint32_t getHP1BL() { return this->_hp1_bl; } // Get baseline resistance of HP1 of last measurement
uint32_t getHP2BL() { return this->_hp2_bl; } // Get baseline resistance of HP2 of last measurement
uint32_t getHP3BL() { return this->_hp3_bl; } // Get baseline resistance of HP3 of last measurement
uint8_t getMISR() { return this->_misr; } // Return status code of sensor
private:
uint8_t _ADDR;
uint8_t _nINT;
uint8_t _nCS;
uint8_t _sdaPin = 0;
uint8_t _sclPin = 0;
#ifndef ENS16x_DISABLE_DEBUG
bool debugENS16x = false;
#endif
bool reset(); // Sends a reset to the ENS16x. Returns false on I2C problems.
bool checkPartID(); // Reads the part ID and confirms valid sensor
bool clearCommand(); // Initialize idle mode and confirms
bool getFirmware(); // Read firmware revisions
bool _available = false; // ENS16x available
uint8_t _revENS16x = 0; // ENS160 or ENS161 connected? (FW >7)
uint8_t _fw_ver_major;
uint8_t _fw_ver_minor;
uint8_t _fw_ver_build;
uint16_t _stepCount; // Counter for custom sequence
uint8_t _data_aqi;
uint16_t _data_tvoc;
uint16_t _data_eco2;
uint16_t _data_aqis;
uint32_t _hp0_rs;
uint32_t _hp0_bl;
uint32_t _hp1_rs;
uint32_t _hp1_bl;
uint32_t _hp2_rs;
uint32_t _hp2_bl;
uint32_t _hp3_rs;
uint32_t _hp3_bl;
uint16_t _temp;
int _slaveaddr;
uint8_t _misr;
//Isotherm, HP0 252°C / HP1 350°C / HP2 250°C / HP3 324°C / measure every 1008ms
uint8_t _seq_steps[1][8] = {
{ 0x7C, 0x0A, 0x7E, 0xAF, 0xAF, 0xA2, 0x00, 0x80 },
};
/****************************************************************************/
/* General functions */
/****************************************************************************/
void _i2c_init();
uint8_t read8(uint8_t addr, byte reg);
uint8_t read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num);
uint8_t write8(uint8_t addr, byte reg, byte value);
uint8_t write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num);
};
#endif

View File

@ -0,0 +1,28 @@
# ENS210
Arduino library for the ENS210 temperature & humidity sensor with I2C interface from ScioSense
## Introduction
This project is an Arduino *library*. It implements a driver with examples for the ENS210.
The ENS210 chip is a digital temperature & humidity sensor with an I2C interface.
The driver in this Arduino library is based on the code supplied by *Sciosense*, the manufacturer of the chip.
Note that the ENS210 requires a supply voltage of 1.71V .. 1.98V.
## Links
The ENS210 is made by [Sciosense](http://www.sciosense.com).
- The datasheet of the ENS210 is not yet released
## Prerequisites
It is assumed that
- The Arduino IDE has been installed.
If not, refer to "Install the Arduino Desktop IDE" on the
[Arduino site](https://www.arduino.cc/en/Guide/HomePage).
- The library directory is at its default location.
For me, Christoph, that is `C:\Users\christoph\Documents\Arduino\libraries`.
## Build an example
To build an example sketch
- (Re)start Arduino.
- Open File > Example > Examples from Custom Libraries > ENS210 > ENS210basic.
- Make sure Tools > Board lists the correct board.
- Select Sketch > Verify/Compile.

View File

@ -0,0 +1,53 @@
#######################################
# Syntax Coloring Map
#######################################
# https://spencer.bliven.us/index.php/2012/01/18/arduino-ide-keywords/
# KEYWORD1 Classes, datatypes, and C++ keywords
# KEYWORD2 Methods and functions
# KEYWORD3 setup and loop functions, as well as the Serial keywords
# LITERAL1 Constants
# LITERAL2 Built-in variables (unused by default)
#######################################
# Classes, datatypes (KEYWORD1)
#######################################
ENS210 KEYWORD1
ens210 KEYWORD1
sciosense_ens210 KEYWORD1
Sciosense_ens210 KEYWORD1
ScioSense_ens210 KEYWORD1
sciosense_ENS210 KEYWORD1
Sciosense_ENS210 KEYWORD1
ScioSense_ENS210 KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
setSingleMode KEYWORD2
available KEYWORD2
getPartID KEYWORD2
getHighUID KEYWORD2
measure KEYWORD2
getTempKelvin KEYWORD2
getTempCelsius KEYWORD2
getTempFahrenheit KEYWORD2
getHumidityPercent KEYWORD2
getAbsoluteHumidityPercent KEYWORD2
getStatusT KEYWORD2
getDataT KEYWORD2
getStatusH KEYWORD2
getDataH KEYWORD2
status_str KEYWORD2
correction_set KEYWORD2
correction_get KEYWORD2
######################################
# Constants (LITERAL1)
#######################################
ENS210_STATUS_I2CERROR LITERAL1
ENS210_STATUS_CRCERROR LITERAL1
ENS210_STATUS_INVALID LITERAL1
ENS210_STATUS_OK LITERAL1

View File

@ -0,0 +1,9 @@
name=ScioSense ENS210
version=3.0.0
author=Christoph Friese
maintainer=Christoph Friese
sentence=Arduino library for the ENS210 digital temperature & humidity sensor with I2C interface from ScioSense
paragraph=This library controls the ENS210. The main feature of this library is performing a single shot measurement, retrieving the measurement data.
category=Device Control
url=https://github.com/sciosense/ens210
architectures=*

View File

@ -0,0 +1,648 @@
/*
ScioSense_ENS210.h - Library for the ENS210 relative humidity and temperature sensor with I2C interface from ScioSense
2020 Apr 06 v3 Christoph Friese Changed nomenclature to ScioSense as product shifted from ams
2018 Aug 28 v2 Christoph Friese Adjusted I2C communication
2017 Aug 01 v1 Maarten Pennings Created
*/
#include "ScioSense_ENS210.h"
#include <assert.h>
// Compute the CRC-7 of 'val' (should only have 17 bits)
// https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Computation
static uint32_t crc7( uint32_t val )
{
// Setup polynomial
uint32_t pol= CRC7POLY;
// Align polynomial with data
pol = pol << (DATA7WIDTH-CRC7WIDTH-1);
// Loop variable (indicates which bit to test, start with highest)
uint32_t bit = DATA7MSB;
// Make room for CRC value
val = val << CRC7WIDTH;
bit = bit << CRC7WIDTH;
pol = pol << CRC7WIDTH;
// Insert initial vector
val |= CRC7IVEC;
// Apply division until all bits done
while( bit & (DATA7MASK<<CRC7WIDTH) ) {
if( bit & val ) val ^= pol;
bit >>= 1;
pol >>= 1;
}
return val;
}
ScioSense_ENS210::ScioSense_ENS210(uint8_t slaveaddr) {
this->_slaveaddress = slaveaddr;
}
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
void ScioSense_ENS210::setI2C(uint8_t sda, uint8_t scl) {
this->_sdaPin = sda;
this->_sclPin = scl;
}
#endif
// Init I2C communication, resets ENS210 and checks its PART_ID. Returns false on I2C problems or wrong PART_ID.
// Stores solder correction.
bool ScioSense_ENS210::begin(bool debug) {
bool result;
#ifndef ENS210_DISABLE_DEBUG
debugENS210 = debug;
#endif
//init I2C
_i2c_init();
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.println("ens210 debug - I2C init done");
}
#endif
// Record solder correction
this->_soldercorrection= 0;
this->_available = false;
this->_singleMode = true;
this->_t_data = -1;
this->_h_data = -1;
this->_partID = 0;
this->lowpower(false);
result = this->getversion();
if(this->_partID == ENS210_PARTID ) {
this->_available = true;
}
return result;
}
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
void ScioSense_ENS210::changeAddr(uint8_t oldAddr, uint8_t newAddr) {
uint8_t i2cbuf[2];
_i2c_init();
//Disable low power mode --> always on
uint8_t result = this->write8(oldAddr, 0x10, 0x00);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Low Power off result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
// read status register
result = this->read(oldAddr, 0x11, i2cbuf, 1);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Read status result: 0x");
Serial.println(result,HEX);
for (uint8_t i=0; i<1; i++) {
Serial.print("\t0x");
Serial.print(i2cbuf[i],HEX);
}
Serial.println();
#endif
delay(100);
// enable low level access. PASSWORD_WRITE_ENABLE
result = this->write8(oldAddr, 0x10, 0x30);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("PASSWORD_WRITE_ENABLE result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
// read status register
result = this->read(oldAddr, 0x11, i2cbuf, 1);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Read status result: 0x");
Serial.println(result,HEX);
for (uint8_t i=0; i<1; i++) {
Serial.print("\t0x");
Serial.print(i2cbuf[i],HEX);
}
Serial.println();
#endif
delay(100);
// low level access password. Password is 00 00 00 00
uint8_t passwdCmd[4] = {0x00, 0x00, 0x00, 0x00};
result = this->write(oldAddr, 0x48, passwdCmd, 5);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Write password result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
// read low-level mode sensor output data
result = this->read(oldAddr, 0x46, i2cbuf, 2);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Read low level result: 0x");
Serial.println(result,HEX);
for (uint8_t i=0; i<2; i++) {
Serial.print("\t0x");
Serial.print(i2cbuf[i],HEX);
}
Serial.println();
#endif
delay(100);
// write values to parameter field and data1&2 field
uint8_t newAddrCmd[5] = {0x00,0x00,0x22,0x00,0x41};
newAddrCmd[4] = newAddr;
result = this->write(oldAddr, 0x41, newAddrCmd, 5);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Write parameters result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
// write SEN_CMD to execute low-level command specified, 0xCE means “APB_WRITE”
result = this->write8(oldAddr, 0x40, 0xCE);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Execute result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
// Read low-level mode sensor output data to check if programming succeeded. Expected response: 0x00 0xAC
result = this->read(oldAddr, 0x46, i2cbuf, 2);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Read back result: 0x");
Serial.println(result,HEX);
for (uint8_t i=0; i<2; i++) {
Serial.print("\t0x");
Serial.print(i2cbuf[i],HEX);
}
Serial.println();
#endif
delay(100);
// reset ENS210
result = this->write8(oldAddr, 0x10, 0xFF);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Reset result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
// reset ENS210
result = this->write8(oldAddr, 0x10, 0xFF);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Reset result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
// reset ENS210
result = this->write8(newAddr, 0x10, 0xFF);
#ifndef ENS210_DISABLE_DEBUG
Serial.print("Reset result: 0x");
Serial.println(result,HEX);
#endif
delay(100);
}
#endif //#ifndef ENS210_DISABLE_ENHANCED_FEATURES
// Sends a reset to the ENS210. Returns false on I2C problems.
bool ScioSense_ENS210::reset(void) {
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SYS_CTRL, 0x80);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - reset: 0x");
Serial.println(result,HEX);
}
#endif
delay(ENS210_BOOTING); // Wait to boot after reset
return result==0;
}
// Sets ENS210 to low (true) or high (false) power. Returns false on I2C problems.
bool ScioSense_ENS210::lowpower(bool enable) {
uint8_t power = enable ? 0x01: 0x00;
uint8_t result = this->write8(this->_slaveaddress, ENS210_REG_SYS_CTRL, power);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - lowpower: 0x");
Serial.println(result,HEX);
}
#endif
delay(ENS210_BOOTING); // Wait boot-time after power switch
return result==0;
}
// Reads PART_ID and UID of ENS210. Returns false on I2C problems.
bool ScioSense_ENS210::getversion() {
bool ok;
uint8_t i2cbuf[8];
uint8_t result;
// Must disable low power to read PART_ID or UID
ok= lowpower(false); if(!ok) goto errorexit;
// Read the PART_ID
result = this->read(this->_slaveaddress, ENS210_REG_PART_ID, i2cbuf, 2);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - PART_ID I2C result: 0x");
Serial.println(result, HEX);
}
#endif
//this->_partID = (uint16_t)(i2cbuf[1]*256U + i2cbuf[0]*1U);
this->_partID = (uint16_t)(((uint16_t)i2cbuf[1] << 8) | ((uint16_t)i2cbuf[0]));
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("PART_ID: 0x");
Serial.println(this->_partID,HEX);
}
#endif
// Read the REV
result = this->read(this->_slaveaddress, ENS210_REG_REV, i2cbuf, 2);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - REV I2C result: 0x");
Serial.println(result, HEX);
}
#endif
this->_rev = (uint16_t)(((uint16_t)i2cbuf[1] << 8) | ((uint16_t)i2cbuf[0]));
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("REV: 0x");
Serial.println(this->_rev,HEX);
}
#endif
// Read the UID
result = this->read(_slaveaddress, ENS210_REG_UID,i2cbuf,8);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - UID 0x");
Serial.println(result,HEX);
}
#endif
this->_uID = (uint64_t)((uint64_t)i2cbuf[7]<<56 | (uint64_t)i2cbuf[6]<<48 | (uint64_t)i2cbuf[5]<<40 | (uint64_t)i2cbuf[4]<<32 | (uint64_t)i2cbuf[3]<<24 | (uint64_t)i2cbuf[2]<<16 | (uint64_t)i2cbuf[1]<<8 | (uint64_t)i2cbuf[0]);
//for( int i=0; i<8; i++) ((uint8_t*)this->_uID)[i]=i2cbuf[i]; //((uint8_t*)this->_uID)[i]=i2cbuf[i];
this->_uIDhi = (uint32_t)(this->_uID >> 32);
this->_uIDlo = (uint32_t)(this->_uID & 0xFFFFFFFF);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("UID hi 0x");
Serial.print(this->_uIDhi,HEX);
Serial.print(" - 0x");
Serial.println(this->_uIDlo,HEX);
}
#endif
// Go back to default power mode (low power enabled)
ok= lowpower(true); if(!ok) goto errorexit;
// Success
return true;
errorexit:
// Try to go back to default mode (low power enabled)
ok= lowpower(true);
// Hopefully enabling low power was successful; but there was an error before that anyhow
return false;
}
// Configures ENS210 measurement mode
// false for continuous mode / true for single shot measurement. Returns false on I2C problems.
bool ScioSense_ENS210::setSingleMode(bool enable)
{
this->_singleMode = enable;
uint8_t mode = enable ? 0x00: 0x03;
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_RUN, mode);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - start mode 0x");
Serial.print(mode,HEX);
Serial.print(" - result 0x");
Serial.println(result,HEX);
}
#endif
return result==0;
}
// Performs one single shot temperature and relative humidity measurement.
void ScioSense_ENS210::measure() //int * t_data, int * t_status, int * h_data, int * h_status )
{
bool ok;
// Set default status for early bail out
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) Serial.println("Start measurement");
#endif
this->_t_status = ENS210_STATUS_I2CERROR;
this->_h_status = ENS210_STATUS_I2CERROR;
// Start a single shot measurement
if (this->_singleMode)
{
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_RUN, 0x00);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - start single 0x");
Serial.println(result,HEX);
}
#endif
}
//Trigger measurement
uint8_t result = this->write8(_slaveaddress, ENS210_REG_SENS_START, 0x03);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - trigger measurement 0x");
Serial.println(result,HEX);
}
#endif
// Wait for measurement to complete
if (this->_singleMode) delay(ENS210_THCONV_SINGLE_MS);
else delay(ENS210_THCONV_CONT_MS);
// Get the measurement data
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) Serial.println("Start measurement");
#endif
ok = readValue(); if(!ok) return;
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) Serial.println("Measurement ok");
#endif
}
// Reads measurement data from the ENS210. Returns false on I2C problems.
bool ScioSense_ENS210::readValue() //uint32_t *t_val, uint32_t *h_val)
{
uint8_t i2cbuf[6];
uint8_t valid;
uint32_t crc;
uint32_t payload;
uint8_t crc_ok;
// Read T_VAL and H_VAL
uint8_t result = this->read(_slaveaddress, ENS210_REG_T_VAL, i2cbuf, 6);
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("ens210 debug - readValue:");
Serial.println(result);
Serial.print(i2cbuf[0],HEX); Serial.print("\t");
Serial.print(i2cbuf[1],HEX); Serial.print("\t");
Serial.print(i2cbuf[2],HEX); Serial.print("\t");
Serial.print(i2cbuf[3],HEX); Serial.print("\t");
Serial.print(i2cbuf[4],HEX); Serial.print("\t");
Serial.print(i2cbuf[5],HEX); Serial.println("\t");
}
#endif
// Retrieve and pack bytes into t_val and h_val
uint32_t t_val= (uint32_t)((uint32_t)i2cbuf[2]<<16 | (uint32_t)i2cbuf[1]<<8 | (uint32_t)i2cbuf[0]);
this->_t_data = (t_val>>0) & 0xffff;
valid = (t_val>>16) & 0x1;
crc = (t_val>>17) & 0x7f;
payload = (t_val>>0 ) & 0x1ffff;
crc_ok = crc7(payload)==crc;
if( !crc_ok ) this->_t_status = ENS210_STATUS_CRCERROR;
else if( !valid ) this->_t_status = ENS210_STATUS_INVALID;
else this->_t_status = ENS210_STATUS_OK;
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("_t_data 0x");
Serial.print(t_val,HEX);
Serial.print(" - 0x");
Serial.println(this->_t_data,HEX);
Serial.print("Valid: ");
Serial.print(valid);
Serial.print(" Status: ");
Serial.println(this->_t_status);
}
#endif
uint32_t h_val= (uint32_t)((uint32_t)i2cbuf[5]<<16 | (uint32_t)i2cbuf[4]<<8 | (uint32_t)i2cbuf[3]);
this->_h_data = (h_val>>0) & 0xffff;
valid = (h_val>>16) & 0x1;
crc = (h_val>>17) & 0x7f;
payload = (h_val>>0 ) & 0x1ffff;
crc_ok= crc7(payload)==crc;
if( !crc_ok ) this->_h_status= ENS210_STATUS_CRCERROR;
else if( !valid ) this->_h_status= ENS210_STATUS_INVALID;
else this->_h_status= ENS210_STATUS_OK;
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("_h_data 0x");
Serial.print(h_val,HEX);
Serial.print(" - 0x");
Serial.println(this->_h_data,HEX);
Serial.print("Valid: ");
Serial.print(valid);
Serial.print(" Status: ");
Serial.println(this->_h_status);
}
#endif
// Success
return true;
}
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
// Converts a status (ENS210_STATUS_XXX) to a human readable string.
const char * ScioSense_ENS210::status_str( int status )
{
switch( status ) {
case ENS210_STATUS_I2CERROR : return "i2c-error";
case ENS210_STATUS_CRCERROR : return "crc-error";
case ENS210_STATUS_INVALID : return "data-invalid";
case ENS210_STATUS_OK : return "ok";
default : return "unknown-status";
}
}
#endif
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
// Convert raw `t_data` temperature to Kelvin (also applies the solder correction).
// The output value is in Kelvin multiplied by parameter `multiplier`.
float ScioSense_ENS210::getTempKelvin()
{
// Force 32 bits
float t = this->_t_data & 0xFFFF;
// Compensate for soldering effect
t-= _soldercorrection;
// Return m*K. This equals m*(t/64) = (m*t)/64
// Note m is the multiplier, K is temperature in Kelvin, t is raw t_data value.
// Uses K=t/64.
return t/64; //IDIV(t,64);
}
#endif
// Convert raw `t_data` temperature to Celsius (also applies the solder correction).
// The output value is in Celsius multiplied by parameter `multiplier`.
float ScioSense_ENS210::getTempCelsius()
{
//assert( (1<=multiplier) && (multiplier<=1024) );
// Force 32 bits
float t= this->_t_data & 0xFFFF;
// Compensate for soldering effect
t-= _soldercorrection;
// Return m*C. This equals m*(K-273.15) = m*K - 27315*m/100 = m*t/64 - 27315*m/100
// Note m is the multiplier, C is temperature in Celsius, K is temperature in Kelvin, t is raw t_data value.
// Uses C=K-273.15 and K=t/64.
return t/64 - 27315L/100; //IDIV(t,64) - IDIV(27315L,100);
}
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
// Convert raw `t_data` temperature to Fahrenheit (also applies the solder correction).
float ScioSense_ENS210::getTempFahrenheit()
{
float t= this->_t_data & 0xFFFF;
// Compensate for soldering effect
t-= _soldercorrection;
// Return m*F. This equals m*(1.8*(K-273.15)+32) = m*(1.8*K-273.15*1.8+32) = 1.8*m*K-459.67*m = 9*m*K/5 - 45967*m/100 = 9*m*t/320 - 45967*m/100
// Note m is the multiplier, F is temperature in Fahrenheit, K is temperature in Kelvin, t is raw t_data value.
// Uses F=1.8*(K-273.15)+32 and K=t/64.
return 9*t/320 - 45967/100; //IDIV(9*t,320) - IDIV(45967L,100);
// The first multiplication stays below 32 bits (t:16, multiplier:11, 9:4)
// The second multiplication stays below 32 bits (multiplier:10, 45967:16)
}
#endif
// Convert raw `h_data` relative humidity to %RH.
float ScioSense_ENS210::getHumidityPercent()
{
float h= this->_h_data & 0xFFFF;
// Return m*H. This equals m*(h/512) = (m*h)/512
// Note m is the multiplier, H is the relative humidity in %RH, h is raw h_data value.
// Uses H=h/512.
return h/512; //IDIV(h, 512);
}
// Convert raw `h_data` absolute humidity to %RH.
#define MOLAR_MASS_OF_WATER 18.01534
#define UNIVERSAL_GAS_CONSTANT 8.21447215
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
float ScioSense_ENS210::getAbsoluteHumidityPercent()
{
//taken from https://carnotcycle.wordpress.com/2012/08/04/how-to-convert-relative-humidity-to-absolute-humidity/
//precision is about 0.1°C in range -30 to 35°C
//August-Roche-Magnus 6.1094 exp(17.625 x T)/(T + 243.04)
//Buck (1981) 6.1121 exp(17.502 x T)/(T + 240.97)
//reference https://www.eas.ualberta.ca/jdwilson/EAS372_13/Vomel_CIRES_satvpformulae.html // Use Buck (1981)
return (6.1121 * pow(2.718281828,(17.67* this->getTempCelsius())/(this->getTempCelsius() + 243.5))* this->getHumidityPercent() *MOLAR_MASS_OF_WATER)/((273.15+ this->getTempCelsius() )*UNIVERSAL_GAS_CONSTANT);
}
#endif
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
// Sets the solder correction (default is 50mK) - only used by the `toXxx` functions.
void ScioSense_ENS210::correction_set(int correction)
{
assert( -1*64<correction && correction<+1*64 ); // A correction of more than 1 Kelvin does not make sense (but the 1K is arbitrary)
this->_soldercorrection = correction;
}
#endif
/****************************************************************************/
/* General functions */
/****************************************************************************/
void ScioSense_ENS210::_i2c_init() {
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
if (this->_sdaPin != this->_sclPin)
Wire.begin(this->_sdaPin, this->_sclPin);
else
#endif
Wire.begin();
}
/**************************************************************************/
uint8_t ScioSense_ENS210::read8(uint8_t addr, byte reg)
{
uint8_t ret;
this->read(addr, reg, &ret, 1);
return ret;
}
uint8_t ScioSense_ENS210::read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num)
{
uint8_t pos = 0;
uint8_t result = 0;
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("I2C read address: 0x");
Serial.print(addr, HEX);
Serial.print(" - register: 0x");
Serial.println(reg, HEX);
}
#endif
//on arduino we need to read in 32 byte chunks
while(pos < num){
uint8_t read_now = 32; //min((uint8_t)32, (uint8_t)(num - pos));
Wire.beginTransmission((uint8_t)addr);
Wire.write((uint8_t)reg + pos);
result = Wire.endTransmission();
Wire.requestFrom((uint8_t)addr, read_now);
//for(int i=0; i<read_now; i++){
for(int i=0; i<num; i++){
buf[pos] = Wire.read();
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("Pos: ");
Serial.print(pos);
Serial.print(" - Value: 0x");
Serial.println(buf[pos], HEX);
}
#endif
pos++;
}
}
return result;
}
/**************************************************************************/
uint8_t ScioSense_ENS210::write8(uint8_t addr, byte reg, byte value)
{
uint8_t result = this->write(addr, reg, &value, 1);
return result;
}
uint8_t ScioSense_ENS210::write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num)
{
#ifndef ENS210_DISABLE_DEBUG
if (debugENS210) {
Serial.print("I2C write address: 0x");
Serial.print(addr, HEX);
Serial.print(" - register: 0x");
Serial.print(reg, HEX);
Serial.print(" - value: 0x");
for (int i = 0; i<num; i++) {
Serial.print(" 0x");
Serial.print(buf[i], HEX);
}
Serial.println();
}
#endif
Wire.beginTransmission((uint8_t)addr);
Wire.write((uint8_t)reg);
Wire.write((uint8_t *)buf, num);
uint8_t result = Wire.endTransmission();
return result;
}

View File

@ -0,0 +1,149 @@
/*
ScioSense_ENS210.h - Library for the ENS210 relative humidity and temperature sensor with I2C interface from ScioSense
2020 Apr 06 v3 Chrsitoph Friese Changed nomenclature to ScioSense as product shifted from ams
2018 Aug 28 v2 Christoph Friese Adjusted I2C communication
2017 Aug 01 v1 Maarten Pennings Created
*/
#ifndef __SCIOSENSE_ENS210_H_
#define __SCIOSENSE_ENS210_H_
#define ENS210_DISABLE_DEBUG
#define ENS210_DISABLE_ENHANCED_FEATURES
#if (ARDUINO >= 100)
#include "Arduino.h"
#else
#include "WProgram.h"
#endif
#include <Wire.h>
#define ENS210_I2CADDR 0x43 //ADDR low
// Chip constants
#define ENS210_PARTID 0x0210 // The expected part id of the ENS210
#define ENS210_BOOTING 2 // Booting time in ms (also after reset, or going to high power)
#define ENS210_THCONV_SINGLE_MS 130 // Conversion time in ms for single shot T/H measurement
#define ENS210_THCONV_CONT_MS 238 // Conversion time in ms for continuous T/H measurement
// Addresses of the ENS210 registers
#define ENS210_REG_PART_ID 0x00
#define ENS210_REG_REV 0x02
#define ENS210_REG_UID 0x04
#define ENS210_REG_SYS_CTRL 0x10
#define ENS210_REG_SYS_STAT 0x11
#define ENS210_REG_SENS_RUN 0x21
#define ENS210_REG_SENS_START 0x22
#define ENS210_REG_SENS_STOP 0x23
#define ENS210_REG_SENS_STAT 0x24
#define ENS210_REG_T_VAL 0x30
#define ENS210_REG_H_VAL 0x33
// Division macro (used in conversion functions), implementing integer division with rounding.
// It supports both positive and negative dividends (n), but ONLY positive divisors (d).
//#define IDIV(n,d) ((n)>0 ? ((n)+(d)/2)/(d) : ((n)-(d)/2)/(d))
// 7654 3210
// Polynomial 0b 1000 1001 ~ x^7+x^3+x^0
// 0x 8 9
#define CRC7WIDTH 7 // A 7 bits CRC has polynomial of 7th order, which has 8 terms
#define CRC7POLY 0x89 // The 8 coefficients of the polynomial
#define CRC7IVEC 0x7F // Initial vector has all 7 bits high
// Payload data
#define DATA7WIDTH 17
#define DATA7MASK ((1UL<<DATA7WIDTH)-1) // 0b 0 1111 1111 1111 1111
#define DATA7MSB (1UL<<(DATA7WIDTH-1)) // 0b 1 0000 0000 0000 0000
// Measurement status as output by `measure()` and `extract()`.
// Note that the ENS210 provides a "value" (`t_val` or `h_val` each 24 bit).
// A "value" consists of a payload (17 bit) and a CRC (7 bit) over that payload.
// The payload consists of a valid flag (1 bit) and the actual measurement "data" (`t_data` or `h_data`, 16 bit)
#define ENS210_STATUS_I2CERROR 4 // There was an I2C communication error, `read`ing the value.
#define ENS210_STATUS_CRCERROR 3 // The value was read, but the CRC over the payload (valid and data) does not match.
#define ENS210_STATUS_INVALID 2 // The value was read, the CRC matches, but the data is invalid (e.g. the measurement was not yet finished).
#define ENS210_STATUS_OK 1 // The value was read, the CRC matches, and data is valid.
class ScioSense_ENS210 {
public:
ScioSense_ENS210(uint8_t slaveaddr = ENS210_I2CADDR);
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
void setI2C(uint8_t sda, uint8_t scl);
void changeAddr(uint8_t oldAddr, uint8_t newAddr);
#endif
bool begin(bool debug=false); // init i2c interface, get partID und uID. Returns false on I2C problems or wrong PART_ID.
bool setSingleMode(bool enable); // false for continuous mode / true for single shot measurement. Returns false on I2C problems.
bool available() { return this->_available; }
uint16_t getPartID() { return this->_partID; }
uint16_t getRev() { return this->_rev; }
uint32_t getHighUID(bool high) { uint32_t result = high ? this->_uIDhi : this->_uIDlo; return result; }
void measure(); // perfrom measurement and stores result in internal variables
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
float getTempKelvin (); // Converts and returns data (from `measure`) in Kelvin
float getTempFahrenheit (); // Converts and returns data (from `measure`) in Fahrenheit
#endif
float getTempCelsius (); // Converts and returns data (from `measure`) in Celsius
float getHumidityPercent(); // Converts and returns data (from `measure`) in %RH
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
float getAbsoluteHumidityPercent(); // Converts and returns data (from `measure`) in %aH
#endif
char getStatusT() { return this->_t_status; } // Converts a status (ENS210_STATUS_XXX) to a human readable string.
uint32_t getDataT() { return this->_t_data; }
char getStatusH() { return this->_h_status; } // Converts a status (ENS210_STATUS_XXX) to a human readable string.
uint32_t getDataH() { return this->_h_data; }
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
static const char * status_str( int status ); // Converts a status (ENS210_STATUS_XXX) to a human readable string.
#endif
// Optionally set a solder `correction` (units: 1/64K, default from `begin` is 0).
// See "Effect of Soldering on Temperature Readout" in "Design-Guidelines" from
// https://download.ams.com/ENVIRONMENTAL-SENSORS/ENS210/Documentation
#ifndef ENS210_DISABLE_ENHANCED_FEATURES
void correction_set(int correction=50*64/1000); // Sets the solder correction (default is 50mK) - only used by the `toXxx()` functions.
int correction_get() {return this->_soldercorrection;} // Gets the solder correction.
#endif
private:
#ifndef ENS210_DISABLE_DEBUG
bool debugENS210 = false;
#endif
bool reset(void); // Sends a reset to the ENS210. Returns false on I2C problems.
bool lowpower(bool enable); // Sets ENS210 to low (true) or high (false) power. Returns false on I2C problems.
bool getversion(); // Reads PART_ID and UID of ENS210. Returns false on I2C problems.
bool readValue(); // Reads measurement data from the ENS210. Returns false on I2C problems.
bool _available = false; // ENS210 available
uint16_t _partID; // Part ID of ENS210, should be 0x210
uint16_t _rev; // Revision 0 MRA2.6 / 1 MRA2.12
uint64_t _uID; // Unique ID of this specific ENS210
uint32_t _uIDhi; // First 32bit of unique ID of this specific ENS210
uint32_t _uIDlo; // Second 32bit of unique ID of this specific ENS210
bool _singleMode = true; // Measurement mode: true single shot / false continuous
uint32_t _t_data;
uint8_t _t_status;
uint32_t _h_data;
uint8_t _h_status;
uint8_t _slaveaddress = 0x43; // Slave address of ENS210
uint8_t _soldercorrection; // Correction due to soldering (in 1/64K); subtracted from `t_data` by conversion functions.
uint8_t _sdaPin = 0;
uint8_t _sclPin = 0;
/****************************************************************************/
/* General functions */
/****************************************************************************/
uint8_t write8(uint8_t addr, byte reg, byte value);
uint8_t read8(uint8_t addr, byte reg);
uint8_t read(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num);
uint8_t write(uint8_t addr, uint8_t reg, uint8_t *buf, uint8_t num);
void _i2c_init();
};
#endif

View File

@ -52,7 +52,7 @@ uint16_t SensirionI2CCommunication::sendFrame(uint8_t address,
size_t writtenBytes = i2cBus.write(frame._buffer, frame._index);
uint8_t i2c_error = i2cBus.endTransmission();
if (writtenBytes != frame._index) {
return WriteError | I2cOtherError;
return static_cast<uint16_t>(WriteError) | static_cast<uint16_t>(I2cOtherError);
}
// translate Arduino errors, see
// https://www.arduino.cc/en/Reference/WireEndTransmission
@ -60,13 +60,13 @@ uint16_t SensirionI2CCommunication::sendFrame(uint8_t address,
case 0:
return NoError;
case 1:
return WriteError | InternalBufferSizeError;
return static_cast<uint16_t>(WriteError) | static_cast<uint16_t>(InternalBufferSizeError);
case 2:
return WriteError | I2cAddressNack;
return static_cast<uint16_t>(WriteError) | static_cast<uint16_t>(I2cAddressNack);
case 3:
return WriteError | I2cDataNack;
return static_cast<uint16_t>(WriteError) | static_cast<uint16_t>(I2cDataNack);
default:
return WriteError | I2cOtherError;
return static_cast<uint16_t>(WriteError) | static_cast<uint16_t>(I2cOtherError);
}
}
@ -89,19 +89,19 @@ uint16_t SensirionI2CCommunication::receiveFrame(uint8_t address,
#endif
if (numBytes % 3) {
return ReadError | WrongNumberBytesError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(WrongNumberBytesError);
}
if ((numBytes / 3) * 2 > frame._bufferSize) {
return ReadError | BufferSizeError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(BufferSizeError);
}
if (numBytes > sizeBuffer) {
return ReadError | InternalBufferSizeError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(InternalBufferSizeError);
}
readAmount = i2cBus.requestFrom(address, static_cast<uint8_t>(numBytes),
static_cast<uint8_t>(true));
if (numBytes != readAmount) {
return ReadError | NotEnoughDataError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(NotEnoughDataError);
}
do {
frame._buffer[i++] = i2cBus.read();
@ -110,7 +110,7 @@ uint16_t SensirionI2CCommunication::receiveFrame(uint8_t address,
uint8_t expectedCRC = generateCRC(&frame._buffer[i - 2], 2, poly);
if (actualCRC != expectedCRC) {
clearRxBuffer(i2cBus);
return ReadError | CRCError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(CRCError);
}
readAmount -= 3;
} while (readAmount > 0);

View File

@ -68,7 +68,7 @@ SensirionI2CTxFrame SensirionI2CTxFrame::createWithUInt16Command(
uint16_t SensirionI2CTxFrame::addCommand(uint16_t command) {
if (_bufferSize < 2) {
return TxFrameError | BufferSizeError;
return static_cast<uint16_t>(TxFrameError) | static_cast<uint16_t>(BufferSizeError);
}
_buffer[0] = static_cast<uint8_t>((command & 0xFF00) >> 8);
_buffer[1] = static_cast<uint8_t>((command & 0x00FF) >> 0);
@ -130,12 +130,12 @@ uint16_t SensirionI2CTxFrame::addBytes(const uint8_t data[],
uint16_t SensirionI2CTxFrame::_addByte(uint8_t data) {
if (_bufferSize <= _index) {
return TxFrameError | BufferSizeError;
return static_cast<uint16_t>(TxFrameError) | static_cast<uint16_t>(BufferSizeError);
}
_buffer[_index++] = data;
if ((_index - _numCommandBytes) % 3 == 2) {
if (_bufferSize <= _index) {
return TxFrameError | BufferSizeError;
return static_cast<uint16_t>(TxFrameError) | static_cast<uint16_t>(BufferSizeError);
}
uint8_t crc = generateCRC(&_buffer[_index - 2], 2, _polynomial_type);
_buffer[_index++] = crc;

View File

@ -42,7 +42,7 @@ SensirionRxFrame::SensirionRxFrame(uint8_t buffer[], size_t bufferSize)
uint16_t SensirionRxFrame::getUInt32(uint32_t& data) {
if (_numBytes < 4) {
return RxFrameError | NoDataError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(NoDataError);
}
data = static_cast<uint32_t>(_buffer[_index++]) << 24;
data |= static_cast<uint32_t>(_buffer[_index++]) << 16;
@ -61,7 +61,7 @@ uint16_t SensirionRxFrame::getInt32(int32_t& data) {
uint16_t SensirionRxFrame::getUInt16(uint16_t& data) {
if (_numBytes < 2) {
return RxFrameError | NoDataError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(NoDataError);
}
data = static_cast<uint16_t>(_buffer[_index++]) << 8;
data |= static_cast<uint16_t>(_buffer[_index++]);
@ -78,7 +78,7 @@ uint16_t SensirionRxFrame::getInt16(int16_t& data) {
uint16_t SensirionRxFrame::getUInt8(uint8_t& data) {
if (_numBytes < 1) {
return RxFrameError | NoDataError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(NoDataError);
}
data = _buffer[_index++];
_numBytes -= 1;
@ -87,7 +87,7 @@ uint16_t SensirionRxFrame::getUInt8(uint8_t& data) {
uint16_t SensirionRxFrame::getInt8(int8_t& data) {
if (_numBytes < 1) {
return RxFrameError | NoDataError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(NoDataError);
}
data = static_cast<int8_t>(_buffer[_index++]);
_numBytes -= 1;
@ -96,7 +96,7 @@ uint16_t SensirionRxFrame::getInt8(int8_t& data) {
uint16_t SensirionRxFrame::getBool(bool& data) {
if (_numBytes < 1) {
return RxFrameError | NoDataError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(NoDataError);
}
data = static_cast<bool>(_buffer[_index++]);
_numBytes -= 1;
@ -115,7 +115,7 @@ uint16_t SensirionRxFrame::getFloat(float& data) {
uint16_t SensirionRxFrame::getBytes(uint8_t data[], size_t maxBytes) {
if (_numBytes < 1) {
return RxFrameError | NoDataError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(NoDataError);
}
size_t readAmount = maxBytes;
if (_numBytes < maxBytes) {

View File

@ -42,7 +42,7 @@ static uint16_t readByte(uint8_t& data, Stream& serial, unsigned long startTime,
unsigned long timeoutMicros) {
do {
if (micros() - startTime > timeoutMicros) {
return ReadError | TimeoutError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(TimeoutError);
}
} while (!serial.available());
data = serial.read();
@ -70,7 +70,7 @@ uint16_t SensirionShdlcCommunication::sendFrame(SensirionShdlcTxFrame& frame,
Stream& serial) {
size_t writtenBytes = serial.write(&frame._buffer[0], frame._index);
if (writtenBytes != frame._index) {
return WriteError | SerialWriteError;
return static_cast<uint16_t>(WriteError) | static_cast<uint16_t>(SerialWriteError);
}
return NoError;
}
@ -83,7 +83,7 @@ uint16_t SensirionShdlcCommunication::receiveFrame(
uint8_t current = 0;
if (frame._numBytes) {
return ReadError | NonemptyFrameError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(NonemptyFrameError);
}
// Wait for start byte and ignore all other bytes in case a partial frame
@ -121,7 +121,7 @@ uint16_t SensirionShdlcCommunication::receiveFrame(
frame._address + frame._command + frame._state + dataLength;
if (dataLength > frame._bufferSize) {
return RxFrameError | BufferSizeError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(BufferSizeError);
}
size_t i = 0;
@ -142,7 +142,7 @@ uint16_t SensirionShdlcCommunication::receiveFrame(
return error;
}
if (expectedChecksum != actualChecksum) {
return ReadError | ChecksumError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(ChecksumError);
}
uint8_t stop;
@ -151,10 +151,10 @@ uint16_t SensirionShdlcCommunication::receiveFrame(
return error;
}
if (stop != 0x7e) {
return ReadError | StopByteError;
return static_cast<uint16_t>(ReadError) | static_cast<uint16_t>(StopByteError);
}
if (frame._state & 0x7F) {
return ExecutionError | frame._state;
return static_cast<uint16_t>(ExecutionError) | frame._state;
}
frame._dataLength = dataLength;
frame._numBytes = dataLength;
@ -175,10 +175,10 @@ uint16_t SensirionShdlcCommunication::sendAndReceiveFrame(
return error;
}
if (rxFrame.getCommand() != txFrame.getCommand()) {
return RxFrameError | RxCommandError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(RxCommandError);
}
if (rxFrame.getAddress() != txFrame.getAddress()) {
return RxFrameError | RxAddressError;
return static_cast<uint16_t>(RxFrameError) | static_cast<uint16_t>(RxAddressError);
}
return NoError;
}

View File

@ -53,7 +53,7 @@ uint16_t SensirionShdlcTxFrame::finish(void) {
return error;
}
if (_index + 1 > _bufferSize) {
return TxFrameError | BufferSizeError;
return static_cast<uint16_t>(TxFrameError) | BufferSizeError;
}
_buffer[_index++] = 0x7e;
_isFinished = true;
@ -84,7 +84,7 @@ uint16_t SensirionShdlcTxFrame::addInt16(int16_t data) {
uint16_t SensirionShdlcTxFrame::addUInt8(uint8_t data) {
if (_index + 2 > _bufferSize) {
return TxFrameError | BufferSizeError;
return static_cast<uint16_t>(TxFrameError) | BufferSizeError;
}
switch (data) {
case 0x11:

View File

@ -178,6 +178,28 @@ uint16_t SensirionI2CSgp4x::readSelfTestValue(uint16_t& testResult) {
return error;
}
uint16_t SensirionI2CSgp4x::getFeaturesValue(uint16_t& featureResult) {
uint16_t error;
uint8_t buffer[3];
SensirionI2CTxFrame txFrame =
SensirionI2CTxFrame::createWithUInt16Command(0x202F, buffer, 3);
error = SensirionI2CCommunication::sendFrame(SGP4X_I2C_ADDRESS, txFrame,
*_i2cBus);
if (error) {
return error;
}
delay(1); // 1ms delay for feature request
SensirionI2CRxFrame rxFrame(buffer, 3);
error = SensirionI2CCommunication::receiveFrame(SGP4X_I2C_ADDRESS, 3,
rxFrame, *_i2cBus);
error |= rxFrame.getUInt16(featureResult);
return error;
}
uint16_t SensirionI2CSgp4x::turnHeaterOff() {
uint16_t error;
uint8_t buffer[2];

View File

@ -120,6 +120,8 @@ class SensirionI2CSgp4x {
uint16_t sendSelfTestCmd(void);
uint16_t readSelfTestValue(uint16_t& testResult);
uint16_t getFeaturesValue(uint16_t& featureResult);
/**
* turnHeaterOff() - This command turns the hotplate off and stops the
* measurement. Subsequently, the sensor enters the idle mode.

View File

@ -1,21 +1,21 @@
MIT License
Copyright (c) 2020 Mixiaoxiao (Wang Bin)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MIT License
Copyright (c) 2023 mobizt
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,258 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to get, set the access control list.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
IMAP_Rights_List acl_list;
Serial.println("\nGet ACLs...");
if (!imap.getACL("INBOX", &acl_list))
{
Serial.println("Get ACLs failed");
}
else
{
Serial.println("ACL...");
for (size_t i = 0; i < acl_list.size(); i++)
{
MailClient.printf("Identifier: %s, Rights: ", acl_list[i].identifier.c_str());
String r;
for (int j = esp_mail_imap_rights_administer; j < esp_mail_imap_rights_maxType; j++)
{
if (acl_list[i].rights[j])
r += (char)('a' + j);
}
Serial.println(r);
}
}
IMAP_Rights_Info acl;
acl.identifier = "Steve";
acl.rights[esp_mail_imap_rights_administer] = true;
acl.rights[esp_mail_imap_rights_create] = true;
acl.rights[esp_mail_imap_rights_create_c] = true;
acl.rights[esp_mail_imap_rights_delete_message] = true;
acl.rights[esp_mail_imap_rights_delete_d] = true;
acl.rights[esp_mail_imap_rights_delete_mailbox] = true;
acl.rights[esp_mail_imap_rights_expunge] = true;
acl.rights[esp_mail_imap_rights_lookup] = true;
acl.rights[esp_mail_imap_rights_insert] = true;
acl.rights[esp_mail_imap_rights_post] = true;
acl.rights[esp_mail_imap_rights_read] = true;
acl.rights[esp_mail_imap_rights_write] = true;
acl.rights[esp_mail_imap_rights_seen] = true;
Serial.println("\nSet ACLs...");
if (!imap.setACL("INBOX", &acl))
{
Serial.println("Set ACLs failed");
}
else
{
Serial.println("Set ACLs success");
}
Serial.println("\nGet my rights...");
if (!imap.myRights("INBOX", &acl))
{
Serial.println("Set my rights failed");
}
else
{
Serial.print("Rights: ");
String r;
for (int i = esp_mail_imap_rights_administer; i < esp_mail_imap_rights_maxType; i++)
{
if (acl.rights[i])
r += (char)('a' + i);
}
Serial.println(r);
}
Serial.println("\nDelete ACLs...");
if (!imap.deleteACL("INBOX", "Steve"))
{
Serial.println("Set ACLs failed");
}
else
{
Serial.println("Delete ACLs success");
}
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}

View File

@ -0,0 +1,239 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to append message to mailbox.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** Assign SD card type and FS used in src/ESP_Mail_FS.h and
* change the config for that card interfaces in src/extras/SDHelper.h
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <data.h>
#include <ESP_Mail_Client.h>
// required IMAP and SMTP
#if defined(ENABLE_IMAP) && defined(ENABLE_SMTP)
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
}
#endif
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
// required IMAP and SMTP
#if defined(ENABLE_IMAP) && defined(ENABLE_SMTP)
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
ESP_Mail_Message message[2]; // The same usage as SMTP_Message
message[0].sender.name = "Fred Foobar";
message[0].sender.email = "foobar@Blurdybloop.example.COM";
message[0].subject = "afternoon meeting";
message[0].addRecipient("Joe Mooch", "mooch@owatagu.example.net");
message[0].text.content = "Hello Joe, do you think we can meet at 3:30 tomorrow?";
message[0].text.charSet = "us-ascii";
message[0].text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
ESP_Mail_Attachment att[2]; // The same usage as SMTP_Attachment
att[0].descr.filename = "shaun.png";
att[0].descr.mime = "image/png";
att[0].blob.data = shaun_png;
att[0].blob.size = sizeof(shaun_png);
att[0].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
message[0].addAttachment(att[0]);
message[1].sender.name = "Joe Mooch";
message[1].sender.email = "mooch@OWaTaGu.example.net";
message[1].subject = "Re: afternoon meeting";
message[1].addRecipient("Fred Foobar", "foobar@blurdybloop.example.com");
message[1].text.content = "3:30 is fine with me.";
message[1].text.charSet = "us-ascii";
message[1].text.transfer_encoding = Content_Transfer_Encoding::enc_7bit;
att[1].descr.filename = "mu_law.wav";
att[1].descr.mime = "audio/basic";
att[1].blob.data = mu_law_wave;
att[1].blob.size = sizeof(mu_law_wave);
att[1].descr.transfer_encoding = Content_Transfer_Encoding::enc_base64;
message[1].addAttachment(att[1]);
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
if (!imap.selectFolder(F("INBOX")))
return;
// If MULTIAPPEND extension is supported, the multiple messages will send by a single APPEND command.
// If not, one message can append for a APPEND command.
// Outlook.com does not accept flag and date/time arguments in APPEND command
if (!MailClient.appendMessage(&imap, &message[0], false /* if not last message to append */, "\\Flagged" /* flags or empty string for Outlook.com */, "Thu, 16 Jun 2022 12:30:25 -0800 (PST)" /* date/time or empty string for Outlook.com */))
MailClient.printf("Message appending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
if (!MailClient.appendMessage(&imap, &message[1], true /* last message to append */))
MailClient.printf("Message appending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
#endif
}
void loop()
{
}

View File

@ -0,0 +1,220 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to copy messages from the mailbox to other folder.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Define the MessageList class to add the message to copy */
MessageList toCopy;
/* Add message uid to copy to the list */
toCopy.add(3);
toCopy.add(4);
// imap.createFolder("test");
/* Copy all messages in the list to the folder "test" */
if (imap.copyMessages(&toCopy, F("test")))
MailClient.printf("\nMessages copied\n");
/* Delete all messages in the list from the opened folder (move to trash) */
// imap.deleteMessages(&toCopy);
// imap.deleteolder("test");
// imap.deleteolder("test2");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,214 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to copy messages from the mailbox to other folder using message numbers ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Copy all messages using message sequence ranges (last 10 message numbers) to the folder "test"*/
int msg_last = imap.selectedFolder().msgCount();
int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last;
String sequence_set2 = String(msg_begin) + ":" + String(msg_last);
if (imap.copyMessages(sequence_set2, false /* if sequence set are message numbers not UIDs */, F("test")))
MailClient.printf("\nCopying messages using message numbers ranges success\n");
else
MailClient.printf("\nError, copying messages using message numbers ranges\n");
// imap.deleteolder("test");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,214 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to copy messages from the mailbox to other folder using UIDs ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Copy all messages using UIDs ranges (last 10 UIDs) to the folder "test" */
int uid_last = imap.getUID(imap.selectedFolder().msgCount());
int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last;
String sequence_set1 = String(uid_begin) + ":" + String(uid_last);
if (imap.copyMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test")))
MailClient.printf("\nCopying messages using UIDs ranges success\n");
else
MailClient.printf("\nError, copying messages using UIDs ranges\n");
// imap.deleteolder("test");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,498 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to read Email with custom character decoding for local language.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** Assign SD card type and FS used in src/ESP_Mail_FS.h and
* change the config for that card interfaces in src/extras/SDHelper.h
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// Provide the SD card interfaces setting and mounting
#include <extras/SDHelper.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Callback function to decode the string based on character set of the content */
void customCharacterDecodingCallback(IMAP_Decoding_Info *decoding);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h
// Mount SD card.
SD_Card_Mounting(); // See src/extras/SDHelper.h
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/* Set the callback function to decode the string based on the caracter set of string */
imap.characterDecodingCallback(customCharacterDecodingCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_sd;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/** Message UID to fetch or read e.g. 100.
* In this case we will get the UID from the max message number (lastest message)
*/
imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount());
// or fetch via the message sequence number
// imap_data.fetch.number = imap.selectedFolder().msgCount();
// if both imap_data.fetch.uid and imap_data.fetch.number were set,
// then total 2 messages will be fetched i.e. one using uid and other using number.
/* Set seen flag */
// The message with "Seen" flagged means the message was already read or seen by user.
// The default value of this option is set to false.
// If you want to set the message flag as "Seen", set this option to true.
// If this option is false, the message flag was unchanged.
// To set or remove flag from message, see Set_Flags.ino example.
// imap_data.fetch.set_seen = true;
/* Read or search the Email and close the session */
// When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status,
// as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag
// to message, see the Set_Flags.ino example.
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
void To_UTF8(IMAP_Decoding_Info *decoding)
{
decoding->decodedString = "fake decoded string "; // return the decoded string
}
void customCharacterDecodingCallback(IMAP_Decoding_Info *decoding)
{
// Serial.println("***** Data Type *****");
// 0 or IMAP_Decoding_Info::message_part_type_header or
// 1 or IMAP_Decoding_Info::message_part_type_text
// Serial.println(decoding->type);
// Serial.println("***** Charset *****");
// Serial.println(decoding->charset);
// Serial.println("***** String to Decode *****");
// Serial.println(decoding->encoded);
// The original or decoded string should be return to the process via
// decoding->decodedString
// Then rturn the decoded string back to the process.
if (strlen(decoding->charset) == 0 || strcasecmp(decoding->charset, "utf-8") == 0 || strcasecmp(decoding->charset, "us-ascii") == 0) // return original
decoding->decodedString = decoding->data;
else // decode to UTF-8 or ASCII
To_UTF8(decoding);
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
MailClient.printf(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
/** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and
* the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename
* (> 13 characters) is not support in the SD.h library.
* To show how its original file name, use imap.fileList().
*/
// Serial.println(imap.fileList());
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,221 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to append new message to mailbox using the custom IMAP command.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void customCommandCallback(IMAP_Response res)
{
// The server responses will included tagged and/or untagged data.
// Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case.
// Tagged status responses included OK, NO, BAD, PREAUTH and BYE.
// Untagged data is the information or result of the request which begins with *
// When you send multiple commands with different tag simultaneously,
// tag will be used as command identifier.
MailClient.printf("> C: TAG %s\n", res.tag.c_str());
MailClient.printf("< S: %s\n", res.text.c_str());
if (res.completed)
{
MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str());
}
}
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
/* Connect to the server */
if (!imap.customConnect(&config, customCommandCallback, F("A01") /* tag */))
return;
String cmd = F("LOGIN ");
cmd += AUTHOR_EMAIL;
cmd += F(" ");
cmd += AUTHOR_PASSWORD;
// You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID"
// Do not assign tag to command when you assign tag to the last parameter of function.
imap.sendCustomCommand(cmd, customCommandCallback, F("A02") /* tag */);
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.\n");
else
Serial.println("\nConnected with no Auth.\n");
imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A03") /* tag */);
imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A04") /* tag */);
String appendMsg = "Date: Thu, 16 Jun 2022 12:30:25 -0800 (PST)\r\n";
appendMsg += "From: Jack <jack@host.com>\r\n";
appendMsg += "Subject: Greeting from ESP Mail\r\n";
appendMsg += "To: joe@host.com\r\n";
appendMsg += "Message-Id: <jack@host.com>\r\n";
appendMsg += "MIME-Version: 1.0\r\n";
appendMsg += "Content-Type: text/plain; charset=\"us-ascii\"\r\n";
appendMsg += "Content-transfer-encoding: 7bit\r\n";
appendMsg += "\r\n";
appendMsg += "Hello Joe, this is the append message\r\n";
String appendMsgCmd = "APPEND INBOX {" + String(appendMsg.length()) + "}";
imap.sendCustomCommand(appendMsgCmd, customCommandCallback, F("A05") /* tag */);
imap.sendCustomData(appendMsg, true /* flag states the last data to send */);
}
void loop()
{
}

View File

@ -0,0 +1,197 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to send custom IMAP command and get the response.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void customCommandCallback(IMAP_Response res)
{
// The server responses will included tagged and/or untagged data.
// Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case.
// Tagged status responses included OK, NO, BAD, PREAUTH and BYE.
// Untagged data is the information or result of the request which begins with *
// When you send multiple commands with different tag simultaneously,
// tag will be used as command identifier.
MailClient.printf("> C: TAG %s\n", res.tag.c_str());
MailClient.printf("< S: %s\n", res.text.c_str());
if (res.completed)
{
MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str());
}
}
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
// This debug required for showing debug info from imap.connect
imap.debug(1);
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.\n");
else
Serial.println("\nConnected with no Auth.\n");
// You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID"
// Do not assign tag to command when you assign tag to the last parameter of function.
imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A01") /* tag */);
imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A02") /* tag */);
imap.sendCustomCommand(F("FETCH 1 UID"), customCommandCallback, F("A03") /* tag */);
}
void loop()
{
}

View File

@ -0,0 +1,197 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to send custom IMAP command and get the response.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void customCommandCallback(IMAP_Response res)
{
// The server responses will included tagged and/or untagged data.
// Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case.
// Tagged status responses included OK, NO, BAD, PREAUTH and BYE.
// Untagged data is the information or result of the request which begins with *
// When you send multiple commands with different tag simultaneously,
// tag will be used as command identifier.
MailClient.printf("> C: TAG %s\n", res.tag.c_str());
MailClient.printf("< S: %s\n", res.text.c_str());
if (res.completed)
{
MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str());
}
}
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
/* Connect to the server */
if (!imap.customConnect(&config, customCommandCallback, F("A01") /* tag */))
return;
String cmd = F("LOGIN ");
cmd += AUTHOR_EMAIL;
cmd += F(" ");
cmd += AUTHOR_PASSWORD;
// You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID"
// Do not assign tag to command when you assign tag to the last parameter of function.
imap.sendCustomCommand(cmd, customCommandCallback, F("A02") /* tag */);
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.\n");
else
Serial.println("\nConnected with no Auth.\n");
imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A03") /* tag */);
imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A04") /* tag */);
imap.sendCustomCommand(F("FETCH 1 UID"), customCommandCallback, F("A05") /* tag */);
}
void loop()
{
}

View File

@ -0,0 +1,220 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to receive mailbox updates by sending the custom IMAP command IDLE.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
unsigned long lastIdleTerminatedMillis = 0;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void customCommandCallback(IMAP_Response res)
{
// The server responses will included tagged and/or untagged data.
// Tagged data is the status which begins with command identifier (tag) i.e. "A01" in this case.
// Tagged status responses included OK, NO, BAD, PREAUTH and BYE.
// Untagged data is the information or result of the request which begins with *
// When you send multiple commands with different tag simultaneously,
// tag will be used as command identifier.
MailClient.printf("> C: TAG %s\n", res.tag.c_str());
MailClient.printf("< S: %s\n", res.text.c_str());
if (res.completed)
{
MailClient.printf("> C: Response finished with status %s\n\n", res.status.c_str());
}
}
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
/* Connect to the server */
if (!imap.customConnect(&config, customCommandCallback, F("A01") /* tag */))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.\n");
else
Serial.println("\nConnected with no Auth.\n");
String cmd = F("LOGIN ");
cmd += AUTHOR_EMAIL;
cmd += F(" ");
cmd += AUTHOR_PASSWORD;
// You can also assign tag to the begining of the command e.g. "A01 FETCH 1 UID"
// Do not assign tag to command when you assign tag to the last parameter of function.
imap.sendCustomCommand(cmd, customCommandCallback, F("A02") /* tag */);
imap.sendCustomCommand(F("SELECT \"INBOX\""), customCommandCallback, F("A03") /* tag */);
imap.sendCustomCommand(F("LIST \"\" *"), customCommandCallback, F("A04") /* tag */);
}
void loop()
{
if (imap.connected())
{
if (!imap.sendCustomCommand(F("IDLE"), customCommandCallback, F("A05") /* tag */))
{
// If error, need to re-connect if imap.connected() returns false and re-log in again
Serial.println("\nTCP connection closed!");
return;
}
if (millis() - lastIdleTerminatedMillis > 20 * 60 * 1000) // terminate the IDLE every 20 min.
{
lastIdleTerminatedMillis = millis();
imap.sendCustomCommand(F("DONE"), customCommandCallback, "" /* don't include tag for DONE command */);
}
}
}
/**
* The server MAY consider a client inactive if it has an IDLE command
* running, and if such a server has an inactivity timeout it MAY log
* the client off implicitly at the end of its timeout period. Because
* of that, clients using IDLE are advised to terminate the IDLE and
* re-issue it at least every 29 minutes to avoid being logged off.
*/

View File

@ -0,0 +1,256 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to assign the custom ports with protocols to access IMAP server.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143 // Plain or TLS with STARTTLS
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT esp_mail_imap_port_143
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/** Set the ports and protocols
* The port that assigned with config.server.port will map with the
* protocol assigned here
*/
config.ports_functions.list = new port_function[2];
config.ports_functions.size = 2;
config.ports_functions.list[0].port = 143;
config.ports_functions.list[0].protocol = esp_mail_protocol_tls;
config.ports_functions.list[1].port = 993;
config.ports_functions.list[1].protocol = esp_mail_protocol_ssl;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/* Close the seeion in case the session is still open */
imap.closeSession();
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}

View File

@ -0,0 +1,368 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to read Email and collect the stream data to print or store via the callback function.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** Assign SD card type and FS used in src/ESP_Mail_FS.h and
* change the config for that card interfaces in src/extras/SDHelper.h
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// Provide the SD card interfaces setting and mounting
#include <extras/SDHelper.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
void mimeDataStreamCallback(MIME_Data_Stream_Info streaminfo);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
int progress = 0;
int lastProgress = -1;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h
// Mount SD card.
SD_Card_Mounting(); // See src/extras/SDHelper.h
#endif
/* Set the callback function to get MIME Data stream */
imap.mimeDataStreamCallback(mimeDataStreamCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_sd;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/** Message UID to fetch or read e.g. 100.
* In this case we will get the UID from the max message number (lastest message)
*/
imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount());
/* Set seen flag */
// The message with "Seen" flagged means the message was already read or seen by user.
// The default value of this option is set to false.
// If you want to set the message flag as "Seen", set this option to true.
// If this option is false, the message flag was unchanged.
// To set or remove flag from message, see Set_Flags.ino example.
// imap_data.fetch.set_seen = true;
/* Read or search the Email and close the session */
// When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status,
// as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag
// to message, see the Set_Flags.ino example.
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
void mimeDataStreamCallback(MIME_Data_Stream_Info streaminfo)
{
if (streaminfo.isFirstData)
{
progress = 0;
lastProgress = -1;
Serial.print("Message UID: ");
Serial.println(streaminfo.uid);
Serial.print("Content Type: ");
Serial.println(streaminfo.type);
Serial.print("Content Disposition: ");
Serial.println(streaminfo.disposition);
Serial.print("Text Character Set: ");
Serial.println(streaminfo.charSet);
Serial.print("Content Transfer Encoding: ");
Serial.println(streaminfo.transfer_encoding);
// The total octets of encoded or non-encoded MIME content.
// The size of decoded content may be different.
Serial.print("Total Octets: ");
Serial.println(streaminfo.octet_size);
if (strcmp(streaminfo.disposition, "attachment") == 0 || strcmp(streaminfo.disposition, "inline") == 0)
{
if (strcmp(streaminfo.disposition, "inline") == 0)
{
Serial.print("Content ID: ");
Serial.println(streaminfo.cid);
}
Serial.print("Name: ");
Serial.println(streaminfo.name);
Serial.print("File Name: ");
Serial.println(streaminfo.filename);
Serial.print("Size: ");
Serial.println(streaminfo.size);
Serial.print("Content Description: ");
Serial.println(streaminfo.description);
Serial.print("Creation Date: ");
Serial.println(streaminfo.date);
}
Serial.println("Content:");
}
progress = 100 * streaminfo.octet_count / streaminfo.octet_size;
if (progress != lastProgress && (progress == 0 || progress == 100 || lastProgress + 5 <= progress))
{
lastProgress = progress;
// The size of current decoded chunk data
Serial.print("Data Length: ");
Serial.print(streaminfo.data_size);
Serial.print(", Reading %: ");
Serial.println(progress);
}
// Decoded chunk data is available here
if (streaminfo.data)
{
// If streaminfo.transfer_encoding is 'base64',
// to print or send null terminated string from stream data
/**
char str[streaminfo.data_size + 1];
memcpy(str, streaminfo.data, streaminfo.data_size);
str[streaminfo.data_size] = 0;
Serial.print(str);
*/
// If streaminfo.transfer_encoding is not 'base64', the string can be
// taken directly from casting streaminfo.data as (const char*)streaminfo.data
// To write data to file (if fs is File class object that open in appended mode)
// fs.write((uint8_t *)streaminfo.data, streaminfo.data_size);
// streaminfo.data_size is not more than 512
}
if (streaminfo.isLastData)
{
Serial.println();
Serial.println();
}
}

View File

@ -0,0 +1,218 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to delete messages from the mailbox.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Define the MessageList class to add the message to delete */
MessageList toDelete;
/** Add message uid to delete to the list
* In this case we will delete last 10 messages by get the UID of these message
* and add it to the list
*/
for (int i = imap.selectedFolder().msgCount(); i > (int)imap.selectedFolder().msgCount() - 10 && i > 0; i--)
toDelete.add(imap.getUID(i));
/* Delete all messages in the list (move to trash) */
if (imap.deleteMessages(&toDelete))
Serial.println("\nMessages deleted");
/* Delete all messages permanently by assign the second param to true*/
// imap.deleteMessages(&toDelete, true);
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,229 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to delete messages from the mailbox using message numbers ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Copy all messages using UIDs ranges (last 10 message numbers) to the folder "test" */
int msg_last = imap.selectedFolder().msgCount();
int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last;
String sequence_set1 = String(msg_begin) + ":" + String(msg_last);
if (imap.copyMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test")))
Serial.println("\nCopying messages using message numbers ranges success");
else
Serial.println("\nError, copying messages using message numbers ranges");
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("test")))
return;
delay(10000);
/* Delete all messages using UIDs ranges (last 10 message numbers) from the folder "test" */
msg_last = imap.selectedFolder().msgCount();
msg_begin = msg_last > 10 ? msg_last - 10 : msg_last;
sequence_set1 = String(msg_begin) + ":" + String(msg_last);
if (imap.deleteMessages(sequence_set1, true /* if sequence set are the UIDs */, false))
Serial.println("\nDeleting messages using message numbers ranges success");
else
Serial.println("\nError, Deleting messages using message numbers ranges");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,229 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to delete messages from the mailbox using UIDs ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Copy all messages using UIDs ranges (last 10 UIDs) to the folder "test" */
int uid_last = imap.getUID(imap.selectedFolder().msgCount());
int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last;
String sequence_set1 = String(uid_begin) + ":" + String(uid_last);
if (imap.copyMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test")))
Serial.println("Copying messages using UIDs ranges success");
else
Serial.println("Error, copying messages using UIDs ranges");
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("test")))
return;
delay(10000);
/* Delete all messages using UIDs ranges (last 10 UIDs) from the folder "test" */
uid_last = imap.getUID(imap.selectedFolder().msgCount());
uid_begin = uid_last > 10 ? uid_last - 10 : uid_last;
sequence_set1 = String(uid_begin) + ":" + String(uid_last);
if (imap.deleteMessages(sequence_set1, true /* if sequence set are the UIDs */, false))
Serial.println("Deleting messages using UIDs ranges success");
else
Serial.println("Error, Deleting messages using UIDs ranges");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,334 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
/**
* This example shows how to send Email using EthernetClient.
*
* This example used ESP32 and WIZnet W5500 Ethernet module.
*
* Please see examples/SMTP/Ethernet and examples/SMTP/External_Client for more usage
*/
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
#include <Arduino.h>
#include <ESP_Mail_Client.h>
#include <Ethernet.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
#define IMAP_HOST "<host>"
#define IMAP_PORT 993
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
void imapCallback(IMAP_Status status);
void printAllMailboxesInfo(IMAPSession &imap);
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
IMAPSession imap;
EthernetClient eth_client;
void networkConnection()
{
// Reset the network connection
WiFi.disconnect();
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
Serial.print("Connecting to Wi-Fi");
unsigned long ms = millis();
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
if (millis() - ms >= 5000)
{
Serial.println(" failed!");
return;
}
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
}
void networkStatusRequestCallback()
{
imap.setNetworkStatus(WiFi.status() == WL_CONNECTED);
}
void setup()
{
Serial.begin(115200);
Serial.println();
MailClient.networkReconnect(true);
// The WiFi credentials are required for SAMD21
// due to it does not have reconnect feature.
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
networkConnection();
imap.debug(1);
/*
For internal NTP client
For times east of the Prime Meridian use 0-12
For times west of the Prime Meridian add 12 to the offset.
Ex. American/Denver GMT would be -6. 6 + 12 = 18
See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets
*/
MailClient.setUDPClient(&udp_client, 0 /* GMT offset */);
MailClient.networkReconnect(true);
imap.callback(imapCallback);
Session_Config config;
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
IMAP_Data imap_data;
imap_data.search.criteria.clear();
imap_data.search.unseen_msg = true;
imap_data.storage.saved_path = F("/email_data");
imap_data.storage.type = esp_mail_file_storage_type_flash;
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
imap_data.enable.html = true;
imap_data.enable.text = true;
imap_data.enable.recent_sort = true;
imap_data.enable.download_status = true;
imap_data.limit.search = 5;
imap_data.limit.msg_size = 512;
imap_data.limit.attachment_size = 1024 * 1024 * 5;
imap.setClient(&eth_client);
imap.networkConnectionRequestCallback(networkConnection);
imap.networkStatusRequestCallback(networkStatusRequestCallback);
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
printAllMailboxesInfo(imap);
if (!imap.selectFolder(F("INBOX")))
return;
printSelectedMailboxInfo(imap.selectedFolder());
imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount());
MailClient.readMail(&imap);
imap.empty();
}
void loop()
{
}
void imapCallback(IMAP_Status status)
{
Serial.println(status.info());
if (status.success())
{
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
FoldersCollection folders;
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
for (size_t i = 0; i < msgItems.size(); i++)
{
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,464 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to read Email and update firmware if firmware file name in attachments matches.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// Provide the SD card interfaces setting and mounting
#include <extras/SDHelper.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h
// Mount SD card.
SD_Card_Mounting(); // See src/extras/SDHelper.h
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Assign the attachment filename to compare, update firmware if it matches */
imap_data.firmware_update.attach_filename = "firmware.bin";
/* save (download) firmware to file? */
imap_data.firmware_update.save_to_file = false;
/**
* Device will reboot in if imap.isFirmwareUpdated() returns true in imapCallback function.
* To disable firmware update, call imap_data.firmware_update.attach_filename.clear(); or
* imap_data.firmware_update.attach_filename = "";
*
*/
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/** Message UID to fetch or read e.g. 100.
* In this case we will get the UID from the max message number (lastest message)
*/
imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount());
// or fetch via the message sequence number
// imap_data.fetch.number = imap.selectedFolder().msgCount();
// if both imap_data.fetch.uid and imap_data.fetch.number were set,
// then total 2 messages will be fetched i.e. one using uid and other using number.
/* Set seen flag */
// The message with "Seen" flagged means the message was already read or seen by user.
// The default value of this option is set to false.
// If you want to set the message flag as "Seen", set this option to true.
// If this option is false, the message flag was unchanged.
// To set or remove flag from message, see Set_Flags.ino example.
// imap_data.fetch.set_seen = true;
/* Read or search the Email and close the session */
// When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status,
// as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag
// to message, see the Set_Flags.ino example.
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
if (imap.isFirmwareUpdateSuccess())
{
Serial.println("****************************");
Serial.println("Firmware is already updated, restarting device...");
delay(2000);
#if defined(ESP32) || defined(ESP8266)
ESP.restart();
#elif defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_NANO_RP2040_CONNECT)
rp2040.restart();
#endif
}
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
/** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and
* the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename
* (> 13 characters) is not support in the SD.h library.
* To show how its original file name, use imap.fileList().
*/
// Serial.println(imap.fileList());
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,215 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to get the quota root's resource usage and limits.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
IMAP_Quota_Root_Info info;
Serial.println("\nGet quota root...");
if (!imap.getQuota("", &info))
{
Serial.println("Get quota root failed");
}
else
{
MailClient.printf("Quota root: %s, Resource name: %s, Usage (k): %d, Limit (k): %d\n", info.quota_root.c_str(), info.name.c_str(), (int)info.usage, (int)info.limit);
}
IMAP_Quota_Roots_List quota_roots;
Serial.println("\nGet quota roots list for INBOX folder...");
if (!imap.getQuotaRoot("INBOX", &quota_roots))
{
Serial.println("\nGet quota roots list failed");
}
else
{
for (size_t i = 0; i < quota_roots.size(); i++)
MailClient.printf("%d, Quota root: %s, Resource name: %s, Usage (k): %d, Limit (k): %d\n", (int)i + 1, quota_roots[i].quota_root.c_str(), quota_roots[i].name.c_str(), (int)quota_roots[i].usage, (int)quota_roots[i].limit);
}
Serial.println("\nSet quota root...");
info.name = "STORAGE";
info.limit = 1024 * 1024; // 1048576 k or 1 G.
if (!imap.setQuota("", &info))
{
Serial.println("\nSet quota root failed");
}
else
{
Serial.println("\nSet quota root success");
}
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}

View File

@ -0,0 +1,446 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to get notification in realtime when incoming message arrived and other mailbox changes.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the selected folder update info */
void printPollingStatus(IMAPSession &imap);
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
/* Declare the global used Session_Config for user defined session credentials */
Session_Config config;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void connectWiFi()
{
WiFi.disconnect();
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
}
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
connectWiFi();
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/*
Set the NTP config time
For times east of the Prime Meridian use 0-12
For times west of the Prime Meridian add 12 to the offset.
Ex. American/Denver GMT would be -6. 6 + 12 = 18
See https://en.wikipedia.org/wiki/Time_zone for a list of the GMT/UTC timezone offsets
*/
config.time.ntp_server = F("pool.ntp.org,time.nist.gov");
config.time.gmt_offset = 3;
config.time.day_light_offset = 0;
/** Assign internet connection handler function
* in case of lost internet connection for re-listening the mailbox.
*/
config.network_connection_handler = connectWiFi;
// You can use TCP KeepAlive for more reliable of listen (idle) operation, please read this for detail.
// https://github.com/mobizt/ESP-Mail-Client#using-tcp-session-keepalive-in-esp8266-and-esp32
// You can use keepAlive in ESP8266 core version newer than v3.1.2.
// Or you can use git version (v3.1.2) https://github.com/esp8266/Arduino
#if defined(ESP32)
imap.keepAlive(5, 5, 1);
#endif
/* Set the TCP response read timeout in seconds */
// smtp.setTCPTimeout(10);
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
}
void loop()
{
/* imap.connect and imap.selectFolder or imap.openFolder nedded to be called once prior to listen */
// Listen for mailbox changes
if (!imap.listen())
return;
// Check the changes
if (imap.folderChanged())
printPollingStatus(imap);
// To stop listen, use imap.stopListen(); and to listen again, call imap.listen()
}
void printPollingStatus(IMAPSession &imap)
{
/* Declare the selected folder info class to get the info of selected mailbox folder */
SelectedFolderInfo sFolder = imap.selectedFolder();
/* Show the mailbox info */
MailClient.printf("\nMailbox status changed\n----------------------\nTotal Messages: %d\n", sFolder.msgCount());
if (sFolder.pollingStatus().type == imap_polling_status_type_new_message)
{
MailClient.printf("New message %d, has been addedd, reading message...\n", (int)sFolder.pollingStatus().messageNum);
// if (sFolder.recentCount() > 0)
// MailClient.printf("\nMesssage count which recent flag set: %d\n", sFolder.recentCount());
// we need to stop polling before do anything
imap.stopListen();
// Get the UID of new message and fetch
imap_data.fetch.uid = imap.getUID(sFolder.pollingStatus().messageNum);
MailClient.readMail(&imap, false);
}
else if (sFolder.pollingStatus().type == imap_polling_status_type_remove_message)
MailClient.printf("Message %d, has been removed\n\n", (int)sFolder.pollingStatus().messageNum);
else if (sFolder.pollingStatus().type == imap_polling_status_type_fetch_message)
MailClient.printf("Message %d, has been fetched with the argument %s\n\n", (int)sFolder.pollingStatus().messageNum, sFolder.pollingStatus().argument.c_str());
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("RFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
}
Serial.println();
}
}

View File

@ -0,0 +1,214 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to move messages from the mailbox to other folder.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Define the MessageList class to add the message to move */
MessageList toMove;
/* Add message uid to move to the list */
toMove.add(3);
toMove.add(4);
// imap.createFolder("test");
/* Move all messages in the list to the folder "test" */
if (imap.moveMessages(&toMove, F("test")))
Serial.println("\nMessages moved");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,213 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to move messages from the mailbox to other folder using message numbers ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Move all messages using message sequence ranges (last 10 message numbers) to the folder "test"*/
int msg_last = imap.selectedFolder().msgCount();
int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last;
String sequence_set2 = String(msg_begin) + ":" + String(msg_last);
if (imap.moveMessages(sequence_set2, false /* if sequence set are message numbers not UIDs */, F("test")))
Serial.println("\nMoving messages using message numbers ranges success");
else
Serial.println("\nError, moving messages using message numbers ranges");
// imap.deleteolder("test");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,214 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to move messages from the mailbox to other folder using UIDs ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* Move all messages using UIDs ranges (last 10 UIDs) to the folder "test" */
int uid_last = imap.getUID(imap.selectedFolder().msgCount());
int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last;
String sequence_set1 = String(uid_begin) + ":" + String(uid_last);
if (imap.moveMessages(sequence_set1, true /* if sequence set are the UIDs */, F("test")))
Serial.println("\nMoving messages using UIDs ranges success");
else
Serial.println("\nError, moving messages using UIDs ranges");
// imap.deleteolder("test");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}

View File

@ -0,0 +1,216 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to get the namespaces.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
IMAP_Namespaces_List ns_list;
Serial.println("\nGet namespaces...");
if (!imap.getNamespace(&ns_list))
{
Serial.println("\nGet namespaces failed");
}
else
{
if (ns_list.personal_namespaces.size() > 0)
{
Serial.println("\nPersonal Namespaces...");
for (size_t i = 0; i < ns_list.personal_namespaces.size(); i++)
{
MailClient.printf("Prefix: %s, Delimiter: %s\n", ns_list.personal_namespaces[i].prefix.c_str(), ns_list.personal_namespaces[i].delimiter.c_str());
}
}
if (ns_list.other_users_namespaces.size() > 0)
{
Serial.println("\nOther Users Namespaces...");
for (size_t i = 0; i < ns_list.other_users_namespaces.size(); i++)
{
MailClient.printf("Prefix: %s, Delimiter: %s\n", ns_list.other_users_namespaces[i].prefix.c_str(), ns_list.other_users_namespaces[i].delimiter.c_str());
}
}
if (ns_list.shared_namespaces.size() > 0)
{
Serial.println("\nShared Namespaces...");
for (size_t i = 0; i < ns_list.shared_namespaces.size(); i++)
{
MailClient.printf("Prefix: %s, Delimiter: %s\n", ns_list.shared_namespaces[i].prefix.c_str(), ns_list.shared_namespaces[i].delimiter.c_str());
}
}
}
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}

View File

@ -0,0 +1,472 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example will log in with the SASL XOAUTH2 mechanisme using OAuth2.0 access token.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// To use only IMAP functions, you can exclude the SMTP from compilation, see ESP_Mail_FS.h.
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
/** The OAuth2.0 access token
* The generation, exchange and refresh of the access token are not available
* in this library.
*
* To test this using GMail, get the OAuth2.0 access token from this web site
* https://developers.google.com/oauthplayground/
*
* 1. Select the following scope (in Step 1) from Gmail API V1
* https://mail.google.com/
* https://mail.google.com/
*
* 2. Click Authorize APIs button.
* 3. Cick Exchangeauthorization code for tokens.
* 4. From the response, look at access_token from the JSON payload node.
* 5. Copy that access token and paste to the AUTHOR_ACCESS_TOKEN value.
*
* The token will be expired in 3600 seconds (1 Hr).
* The AUTHOR_EMAIL above is the Email address that you granted to access the Gmail services.
*/
#define AUTHOR_ACCESS_TOKEN "<access token>"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.accessToken = AUTHOR_ACCESS_TOKEN;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Message UID to fetch or read e.g. 100 */
imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount());
/* Set seen flag*/
// imap_data.fetch.set_seen = true;
/* Search criteria */
imap_data.search.criteria.clear();
/* Also search the unseen message */
imap_data.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_flash;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/* Read or search the Email and close the session */
// When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status,
// as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag
// to message, see the Set_Flags.ino example.
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
/** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and
* the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename
* (> 13 characters) is not support in the SD.h library.
* To show how its original file name, use imap.fileList().
*/
// Serial.println(imap.fileList());
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,477 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to read Email using UIDs ranges or message numbers ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** Assign SD card type and FS used in src/ESP_Mail_FS.h and
* change the config for that card interfaces in src/extras/SDHelper.h
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void readEmailsUIDS()
{
int uid_last = imap.getUID(imap.selectedFolder().msgCount());
int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last;
// Fetch last 10 UIDs
String sequence_set = String(uid_begin) + ":" + String(uid_last);
imap_data.fetch.sequence_set.string = sequence_set;
imap_data.fetch.sequence_set.UID = true; // The sequence set are UIDs ranges
imap_data.fetch.sequence_set.headerOnly = true; // Do not fetch the content, header only
MailClient.readMail(&imap, false /* do not close sessiopn */);
imap_data.limit.fetch = 5; // Set the limit of number of messages in the fetch results
}
void readEmailsNumbers()
{
int msg_last = imap.selectedFolder().msgCount();
int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last;
String sequence_set = String(msg_begin) + ":" + String(msg_last);
imap_data.fetch.sequence_set.string = sequence_set;
imap_data.fetch.sequence_set.UID = false; // The sequence set are not UIDs
imap_data.fetch.sequence_set.headerOnly = true; // Do not fetch the content, header only
imap_data.limit.fetch = 5; // Set the limit of number of messages in the fetch results
// Read Email and close session
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
// If ID extension was supported by IMAP server, assign the client identification
// name, version, vendor, os, os_version, support_url, address, command, arguments, environment
// Server ID can be optained from imap.serverID() after calling imap.connect and imap.id.
// imap_data.identification.name = "User";
// imap_data.identification.version = "1.0";
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
// Client identification can be sent to server later with
/**
* IMAP_Identification iden;
* iden.name = "user";
* iden.version = "1.0";
*
* if (imap.id(&iden))
* {
* Serial.println("\nSend Identification success");
* Serial.println(imap.serverID());
* }
* else
* MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
*/
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
Serial.println("::::::::::::::::: Reading Emails using the UIDs ranges ::::::::::::::::");
readEmailsUIDS();
Serial.println("::::::::::: Reading Emails using the message numbers ranges :::::::::::");
readEmailsNumbers();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
/** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and
* the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename
* (> 13 characters) is not support in the SD.h library.
* To show how its original file name, use imap.fileList().
*/
// Serial.println(imap.fileList());
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,516 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to read Email and store the message in SD card.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** Assign SD card type and FS used in src/ESP_Mail_FS.h and
* change the config for that card interfaces in src/extras/SDHelper.h
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// Provide the SD card interfaces setting and mounting
#include <extras/SDHelper.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h
// Mount SD card.
SD_Card_Mounting(); // See src/extras/SDHelper.h
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_sd;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
// If ID extension was supported by IMAP server, assign the client identification
// name, version, vendor, os, os_version, support_url, address, command, arguments, environment
// Server ID can be optained from imap.serverID() after calling imap.connect and imap.id.
// imap_data.identification.name = "User";
// imap_data.identification.version = "1.0";
/* Set the TCP response read timeout in seconds */
// imap.setTCPTimeout(10);
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
/** Or connect without log in and log in later
if (!imap.connect(&config, &imap_data, false))
return;
if (!imap.loginWithPassword(AUTHOR_EMAIL, AUTHOR_PASSWORD))
return;
*/
// Client identification can be sent to server later with
/**
* IMAP_Identification iden;
* iden.name = "user";
* iden.version = "1.0";
*
* if (imap.id(&iden))
* {
* Serial.println("\nSend Identification success");
* Serial.println(imap.serverID());
* }
* else
* MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
*/
if (!imap.isLoggedIn())
{
Serial.println("\nNot yet logged in.");
}
else
{
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
}
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/** Message UID to fetch or read e.g. 100.
* In this case we will get the UID from the max message number (lastest message)
*/
imap_data.fetch.uid = imap.getUID(imap.selectedFolder().msgCount());
// if IMAP server supports CONDSTORE extension, the modification sequence can be assign to fetch command
// Note that modsequence value supports in this library is 32-bit integer
imap_data.fetch.modsequence = 123;
// To fetch only header part
// imap_data.fetch.headerOnly = true;
// or fetch via the message sequence number
// imap_data.fetch.number = imap.selectedFolder().msgCount();
// if both imap_data.fetch.uid and imap_data.fetch.number were set,
// then total 2 messages will be fetched i.e. one using uid and other using number.
/* Set seen flag */
// The message with "Seen" flagged means the message was already read or seen by user.
// The default value of this option is set to false.
// If you want to set the message flag as "Seen", set this option to true.
// If this option is false, the message flag was unchanged.
// To set or remove flag from message, see Set_Flags.ino example.
// imap_data.fetch.set_seen = true;
/* Fetch or read only message header */
// imap_data.fetch.headerOnly = true;
/* Read or search the Email and close the session */
// When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status,
// as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag
// to message, see the Set_Flags.ino example.
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
/** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and
* the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename
* (> 13 characters) is not support in the SD.h library.
* To show how its original file name, use imap.fileList().
*/
// Serial.println(imap.fileList());
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,561 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to read Email repeatedly.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
/** Assign SD card type and FS used in src/ESP_Mail_FS.h and
* change the config for that card interfaces in src/extras/SDHelper.h
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
// Provide the SD card interfaces setting and mounting
#include <extras/SDHelper.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
unsigned long readMillis = 0;
int totalMessage = 0;
int msgNum = 0;
int sign = -1;
/* Declare the global used Session_Config for user defined session credentials */
Session_Config config;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
// For Free Heap checking
#include "HeapStat.h"
HeapStat heapInfo;
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h
// Mount SD card.
SD_Card_Mounting(); // See src/extras/SDHelper.h
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Message UID to fetch or read */
imap_data.fetch.uid.clear();
/* Search criteria */
imap_data.search.criteria.clear();
/* Also search the unseen message */
imap_data.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_sd;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = false;
imap_data.download.text = false;
imap_data.download.html = false;
imap_data.download.attachment = false;
imap_data.download.inlineImg = false;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
// If ID extension was supported by IMAP server, assign the client identification
// name, version, vendor, os, os_version, support_url, address, command, arguments, environment
// Server ID can be optained from imap.serverID() after calling imap.connect and imap.id.
// imap_data.identification.name = "User";
// imap_data.identification.version = "1.0";
/* Set the TCP response read timeout in seconds */
// imap.setTCPTimeout(10);
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
// Client identification can be sent to server later with
/**
* IMAP_Identification iden;
* iden.name = "user";
* iden.version = "1.0";
*
* if (imap.id(&iden))
* {
* Serial.println("\nSend Identification success");
* Serial.println(imap.serverID());
* }
* else
* MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
*/
if (!imap.isLoggedIn())
{
Serial.println("\nNot yet logged in.");
}
else
{
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
}
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
totalMessage = imap.selectedFolder().msgCount();
/* Start fetch from last message */
msgNum = totalMessage;
sign = -1; // count down
/* To start fetch from first message */
// msgNum = 1;
// sign = 1;// count up
}
void loop()
{
if (millis() - readMillis > 10000 || readMillis == 0)
{
readMillis = millis();
// If session was closed, reconnect and re-select the mailbox
if (!imap.connected())
{
if (!imap.connect(&config, &imap_data))
return;
if (!imap.selectFolder(F("INBOX")))
return;
if (totalMessage == 0)
{
totalMessage = imap.selectedFolder().msgCount();
msgNum = totalMessage;
sign = -1;
}
}
if (msgNum <= 0)
{
msgNum = 1;
sign = 1;
}
else if (msgNum >= totalMessage)
{
msgNum = totalMessage;
sign = -1;
}
/* Message number to fetch or read */
imap_data.fetch.number = msgNum;
/* Set seen flag */
// imap_data.fetch.set_seen = true;
/* Fetch or read only message header */
// imap_data.fetch.headerOnly = true;
/** Read or search the Email and keep the TCP session to open
* The second parameter is for close the session.
*/
// When message was fetched or read, the /Seen flag will not set or message remained in unseen or unread status,
// as this is the purpose of library (not UI application), user can set the message status as read by set \Seen flag
// to message, see the Set_Flags.ino example.
if (MailClient.readMail(&imap, false))
msgNum += sign;
/* Clear all stored data in IMAPSession object */
imap.empty();
msgNum += sign;
}
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
// Collect memory info
heapInfo.collect();
// Print memory info
heapInfo.print();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
/** In devices other than ESP8266 and ESP32, if SD card was chosen as filestorage and
* the standard SD.h library included in ESP_Mail_FS.h, files will be renamed due to long filename
* (> 13 characters) is not support in the SD.h library.
* To show how its original file name, use imap.fileList().
*/
// Serial.println(imap.fileList());
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,402 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to read Email repeatedly.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/**
* To use library in silent mode (no debug printing and callback), please define this macro in src/ESP_Mail_FS.h.
* #define SILENT_MODE
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#include <extras/SDHelper.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
#define IMAP_HOST "<host>"
#define IMAP_PORT 993
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
void printImapData(IMAP_Status status);
void printAllMailboxesInfo(IMAPSession &imap);
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
IMAPSession imap;
unsigned long readMillis = 0;
int totalMessage = 0;
int msgNum = 0;
int sign = -1;
Session_Config config;
IMAP_Data imap_data;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
// For Free Heap checking
#include "HeapStat.h"
HeapStat heapInfo;
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
MailClient.networkReconnect(true);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
#if defined(ESP_MAIL_DEFAULT_SD_FS) // defined in src/ESP_Mail_FS.h
// Mount SD card.
SD_Card_Mounting(); // See src/extras/SDHelper.h
#endif
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
imap_data.fetch.uid.clear();
imap_data.search.criteria.clear();
imap_data.search.unseen_msg = true;
imap_data.storage.saved_path = F("/email_data");
imap_data.storage.type = esp_mail_file_storage_type_sd;
imap_data.download.header = false;
imap_data.download.text = false;
imap_data.download.html = false;
imap_data.download.attachment = false;
imap_data.download.inlineImg = false;
imap_data.enable.html = true;
imap_data.enable.text = true;
imap_data.enable.recent_sort = true;
imap_data.enable.download_status = true;
imap_data.limit.search = 5;
imap_data.limit.msg_size = 512;
imap_data.limit.attachment_size = 1024 * 1024 * 5;
if (!imap.connect(&config, &imap_data))
{
MailClient.printf("Connection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
return;
}
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
printAllMailboxesInfo(imap);
if (!imap.selectFolder(F("INBOX")))
{
MailClient.printf("Folder selection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
return;
}
printSelectedMailboxInfo(imap.selectedFolder());
totalMessage = imap.selectedFolder().msgCount();
msgNum = totalMessage;
sign = -1; // count down
}
void loop()
{
if (millis() - readMillis > 10000 || readMillis == 0)
{
readMillis = millis();
if (!imap.connected())
{
if (!imap.connect(&config, &imap_data))
return;
if (!imap.selectFolder(F("INBOX")))
return;
if (totalMessage == 0)
{
totalMessage = imap.selectedFolder().msgCount();
msgNum = totalMessage;
sign = -1;
}
}
if (msgNum <= 0)
{
msgNum = 1;
sign = 1;
}
else if (msgNum >= totalMessage)
{
msgNum = totalMessage;
sign = -1;
}
imap_data.fetch.number = msgNum;
if (MailClient.readMail(&imap, false))
{
printImapData(imap.status());
}
else
{
MailClient.printf("Message reading error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
}
imap.empty();
msgNum += sign;
}
}
void printImapData(IMAP_Status status)
{
if (status.success())
{
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
imap.empty();
heapInfo.collect();
heapInfo.print();
Serial.println();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
FoldersCollection folders;
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
for (size_t i = 0; i < msgItems.size(); i++)
{
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,352 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to search the unread messages and read them.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/**
* To use library in silent mode (no debug printing and callback), please define this macro in src/ESP_Mail_FS.h.
* #define SILENT_MODE
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#include <extras/SDHelper.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
#define IMAP_HOST "<host>"
#define IMAP_PORT 993
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
void imapCallback(IMAP_Status status);
void printAllMailboxesInfo(IMAPSession &imap);
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
void printMessageData();
IMAPSession imap;
Session_Config config;
IMAP_Data imap_data;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
// Max messages in the search result
int max_result = 5;
// Array to store the UID of messages in search result
int msg_uid[5];
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
MailClient.networkReconnect(true);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
// Clear all these fetch options to perform search
imap_data.fetch.uid.clear();
imap_data.fetch.number.clear();
imap_data.fetch.sequence_set.string.clear();
imap_data.search.unseen_msg = true;
// Don't download all to filesystem
imap_data.download.header = false;
imap_data.download.text = false;
imap_data.download.html = false;
imap_data.download.attachment = false;
imap_data.download.inlineImg = false;
// Store html/text message body in IMAPSession object
imap_data.enable.html = true;
imap_data.enable.text = true;
imap_data.enable.recent_sort = true;
// Max messages in the search result
imap_data.limit.search = max_result;
imap_data.limit.msg_size = 128;
if (!imap.connect(&config, &imap_data))
{
MailClient.printf("Connection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
return;
}
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
printAllMailboxesInfo(imap);
if (!imap.selectFolder(F("INBOX")))
{
MailClient.printf("Folder selection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
return;
}
printSelectedMailboxInfo(imap.selectedFolder());
// We search the unseen messages first to get its UID and stored in msg_uid.
imap_data.search.criteria = F("SEARCH UNSEEN");
MailClient.readMail(&imap, false /* keep session open for fetching message in opened mailbox later */);
// We already get the search result message, fetch it
// Fetch the messages using UID stored in msg_uid one by one
for (int i = 0; i < max_result; i++)
{
imap_data.search.criteria.clear();
// Mark this message as read
MailClient.addFlag(&imap, msg_uid[i], F("\\Seen"), false /* Close session */, false /* Ignore response */);
// Now Fech message by UID stored in msg_uid
imap_data.fetch.uid = msg_uid[i];
MailClient.readMail(&imap, false /* keep session open for fetching message in opened mailbox later */);
}
imap.closeSession();
imap.empty();
}
void loop()
{
}
void imapCallback(IMAP_Status status)
{
Serial.println(status.info());
if (status.success())
{
// If this is the search result (imap contains only header info),
// store the message UID that we can fetch for its body later.
if (imap.headerOnly())
{
max_result = imap.data().msgItems.size();
for (size_t i = 0; i < imap.data().msgItems.size(); i++)
msg_uid[i] = imap.data().msgItems[i].UID;
}
else
{
// This is the fetch result, print the whole message (header + body)
printMessageData();
}
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
FoldersCollection folders;
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printMessageData()
{
IMAP_MSG_Item msg = imap.data().msgItems[0]; // msgItems contains only one message from fetch
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
Serial.println();
}

View File

@ -0,0 +1,533 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to search all messages with the keywords in the opened mailbox folder.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143 // Plain or TLS with STARTTLS
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT esp_mail_imap_port_143
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status);
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Print all messages from the message list */
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
/* Print all attachments info from the message */
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/* Set the callback function to get the reading results */
imap.callback(imapCallback);
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/** Declare the IMAP_Data object used for user defined IMAP operating options
* and contains the IMAP operating result
*/
IMAP_Data imap_data;
/* We will clear fetching message UID as it used to determine the reading mode i.e., search and fetch */
imap_data.fetch.uid.clear();
/** Search criteria
*
* A search key can also be a parenthesized list of one or more search keys
* (e.g., for use with the OR and NOT keys).
*
* Since IMAP protocol uses Polish notation, the search criteria which in the polish notation form can be.
*
* To search the message from "someone@email.com" with the subject "my subject" since 1 Jan 2021, your search criteria can be
* UID SEARCH (OR SUBJECT "my subject" FROM "someone@email.com") SINCE "Fri, 1 Jan 2021 21:52:25 -0800"
*
* To search the message from "mail1@domain.com" or from "mail2@domain.com", the search criteria will be
* UID SEARCH OR FROM mail1@domain.com FROM mail2@domain.com
*
* For more details on using parentheses, AND, OR and NOT search keys in search criteria.
* https://www.limilabs.com/blog/imap-search-requires-parentheses
*
*For keywords used in search criteria, see
* https://github.com/mobizt/ESP-Mail-Client/tree/master/src#search-criteria
*
* Use "SEARCH UNSEEN" for unread messages search
* Use "SEARCH RECENT" for messages with the \\RECENT flag set
* Use "ON _date_" for messages with Date header matching _date_
* Use "BEFORE _date_" for messages with Date header before _date_
*/
imap_data.search.criteria = F("SEARCH RECENT");
/* Also search the unseen message */
imap_data.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_flash;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Header fields parsing is case insensitive by default to avoid uppercase header in some server e.g. iCloud
, to allow case sensitive parse, uncomment below line*/
// imap_data.enable.header_case_sensitive = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
// If ID extension was supported by IMAP server, assign the client identification
// name, version, vendor, os, os_version, support_url, address, command, arguments, environment
// Server ID can be optained from imap.serverID() after calling imap.connect and imap.id.
// imap_data.identification.name = "User";
// imap_data.identification.version = "1.0";
/* Set the TCP response read timeout in seconds */
// imap.setTCPTimeout(10);
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
/** Or connect without log in and log in later
if (!imap.connect(&config, &imap_data, false))
return;
if (!imap.loginWithPassword(AUTHOR_EMAIL, AUTHOR_PASSWORD))
return;
*/
// Client identification can be sent to server later with
/**
* IMAP_Identification iden;
* iden.name = "user";
* iden.version = "1.0";
*
* if (imap.id(&iden))
* {
* Serial.println("\nSend Identification success");
* Serial.println(imap.serverID());
* }
* else
* MailClient.printf("nIdentification sending error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
*/
if (!imap.isLoggedIn())
{
Serial.println("\nNot yet logged in.");
}
else
{
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
}
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/** Read or search the Email and keep the TCP session to open
* The second parameter is for close the session.
*/
MailClient.readMail(&imap, false);
/* Clear all stored data in IMAPSession object */
imap.empty();
/** Open or select other mailbox folder
* The folder that previousely opened will be closed
*/
if (imap.selectFolder(F("Junk")))
{
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/** Config to search all messages in the opened mailboax (Search mode)
* For keywords used in search criteria, see
* https://github.com/mobizt/ESP-Mail-Client/tree/master/src#search-criteria
*/
imap_data.search.criteria = F("SEARCH ALL"); // or "SEARCH NEW" for recent received messages
/* We will clear fetching message UID as it used to determine the reading mode i.e., search and fetch */
imap_data.fetch.uid.clear();
/* Search the Email and close the session */
MailClient.readMail(&imap);
}
/* Close the seeion in case the session is still open */
imap.closeSession();
/* Clear all stored data in IMAPSession object */
imap.empty();
}
void loop()
{
}
/* Callback function to get the Email reading status */
void imapCallback(IMAP_Status status)
{
/* Print the current status */
Serial.println(status.info());
/* Show the result when reading finished */
if (status.success())
{
/* Print the result */
/* Get the message list from the message list data */
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
/* Clear all stored data in IMAPSession object */
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
/** att.type can be
* esp_mail_att_type_none or 0
* esp_mail_att_type_attachment or 1
* esp_mail_att_type_inline or 2
*/
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
for (size_t i = 0; i < msgItems.size(); i++)
{
/* Iterate to get each message data through the message item data */
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
// Message sequence number
MailClient.printf("Number: %d\n", msg.msgNo);
// Message UID
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
/* If the result contains the message info (Fetch mode) */
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,327 @@
/**
* Created by K. Suwatchai (Mobizt)
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*/
// This example shows how to search all messages with the keywords in the opened mailbox folder.
/**
* To use library in silent mode (no debug printing and callback), please define this macro in src/ESP_Mail_FS.h.
* #define SILENT_MODE
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
#define IMAP_HOST "<host>"
#define IMAP_PORT esp_mail_imap_port_143
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
void printImapData(IMAP_Status status);
void printAllMailboxesInfo(IMAPSession &imap);
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly);
void printAttacements(std::vector<IMAP_Attach_Item> &atts);
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
MailClient.networkReconnect(true);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
Session_Config config;
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
IMAP_Data imap_data;
imap_data.fetch.uid.clear();
imap_data.search.criteria = F("SEARCH RECENT");
imap_data.search.unseen_msg = true;
imap_data.storage.saved_path = F("/email_data");
imap_data.storage.type = esp_mail_file_storage_type_flash;
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
imap_data.enable.html = true;
imap_data.enable.text = true;
imap_data.enable.recent_sort = true;
imap_data.enable.download_status = true;
imap_data.limit.search = 5;
imap_data.limit.msg_size = 512;
imap_data.limit.attachment_size = 1024 * 1024 * 5;
imap.setTCPTimeout(10);
if (!imap.connect(&config, &imap_data))
{
MailClient.printf("Connection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
return;
}
if (imap.isAuthenticated())
Serial.println("\nSuccessfully logged in.");
else
Serial.println("\nConnected with no Auth.");
printAllMailboxesInfo(imap);
if (!imap.selectFolder(F("INBOX")))
{
MailClient.printf("Folder selection error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
return;
}
printSelectedMailboxInfo(imap.selectedFolder());
if (MailClient.readMail(&imap, false))
{
printImapData(imap.status());
}
else
{
MailClient.printf("Message searching error, Error Code: %d, Reason: %s", imap.errorCode(), imap.errorReason().c_str());
}
imap.closeSession();
imap.empty();
}
void loop()
{
}
void printImapData(IMAP_Status status)
{
if (status.success())
{
MailClient.printf("\nFound %d messages\n\n", imap.selectedFolder().searchCount());
IMAP_MSG_List msgList = imap.data();
printMessages(msgList.msgItems, imap.headerOnly());
imap.empty();
}
}
void printAllMailboxesInfo(IMAPSession &imap)
{
FoldersCollection folders;
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}
void printAttacements(std::vector<IMAP_Attach_Item> &atts)
{
MailClient.printf("Attachment: %d file(s)\n****************************\n", atts.size());
for (size_t j = 0; j < atts.size(); j++)
{
IMAP_Attach_Item att = atts[j];
MailClient.printf("%d. Filename: %s, Name: %s, Size: %d, MIME: %s, Type: %s, Description: %s, Creation Date: %s\n", j + 1, att.filename, att.name, att.size, att.mime, att.type == esp_mail_att_type_attachment ? "attachment" : "inline", att.description, att.creationDate);
}
Serial.println();
}
void printMessages(std::vector<IMAP_MSG_Item> &msgItems, bool headerOnly)
{
for (size_t i = 0; i < msgItems.size(); i++)
{
IMAP_MSG_Item msg = msgItems[i];
Serial.println("****************************");
MailClient.printf("Number: %d\n", msg.msgNo);
MailClient.printf("UID: %d\n", msg.UID);
// The attachment status in search may be true in case the "multipart/mixed"
// content type header was set with no real attachtment included.
MailClient.printf("Attachment: %s\n", msg.hasAttachment ? "yes" : "no");
MailClient.printf("Messsage-ID: %s\n", msg.ID);
if (strlen(msg.flags))
MailClient.printf("Flags: %s\n", msg.flags);
if (strlen(msg.acceptLang))
MailClient.printf("Accept Language: %s\n", msg.acceptLang);
if (strlen(msg.contentLang))
MailClient.printf("Content Language: %s\n", msg.contentLang);
if (strlen(msg.from))
MailClient.printf("From: %s\n", msg.from);
if (strlen(msg.sender))
MailClient.printf("Sender: %s\n", msg.sender);
if (strlen(msg.to))
MailClient.printf("To: %s\n", msg.to);
if (strlen(msg.cc))
MailClient.printf("CC: %s\n", msg.cc);
if (strlen(msg.bcc))
MailClient.printf("BCC: %s\n", msg.bcc);
if (strlen(msg.date))
{
MailClient.printf("Date: %s\n", msg.date);
MailClient.printf("Timestamp: %d\n", (int)MailClient.Time.getTimestamp(msg.date));
}
if (strlen(msg.subject))
MailClient.printf("Subject: %s\n", msg.subject);
if (strlen(msg.reply_to))
MailClient.printf("Reply-To: %s\n", msg.reply_to);
if (strlen(msg.return_path))
MailClient.printf("Return-Path: %s\n", msg.return_path);
if (strlen(msg.in_reply_to))
MailClient.printf("In-Reply-To: %s\n", msg.in_reply_to);
if (strlen(msg.references))
MailClient.printf("References: %s\n", msg.references);
if (strlen(msg.comments))
MailClient.printf("Comments: %s\n", msg.comments);
if (strlen(msg.keywords))
MailClient.printf("Keywords: %s\n", msg.keywords);
if (!headerOnly)
{
if (strlen(msg.text.content))
MailClient.printf("Text Message: %s\n", msg.text.content);
if (strlen(msg.text.charSet))
MailClient.printf("Text Message Charset: %s\n", msg.text.charSet);
if (strlen(msg.text.transfer_encoding))
MailClient.printf("Text Message Transfer Encoding: %s\n", msg.text.transfer_encoding);
if (strlen(msg.html.content))
MailClient.printf("HTML Message: %s\n", msg.html.content);
if (strlen(msg.html.charSet))
MailClient.printf("HTML Message Charset: %s\n", msg.html.charSet);
if (strlen(msg.html.transfer_encoding))
MailClient.printf("HTML Message Transfer Encoding: %s\n\n", msg.html.transfer_encoding);
if (msg.rfc822.size() > 0)
{
MailClient.printf("\r\nRFC822 Messages: %d message(s)\n****************************\n", msg.rfc822.size());
printMessages(msg.rfc822, headerOnly);
}
if (msg.attachments.size() > 0)
printAttacements(msg.attachments);
}
Serial.println();
}
}

View File

@ -0,0 +1,339 @@
/**
* This example shows how to set messages flags.
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*
*/
// This example shows how to set messages flags.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Set seen flag */
// imap_data.fetch.set_seen = true;
/* Search criteria */
imap_data.search.criteria.clear();
/* Also search the unseen message */
imap_data.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_flash;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/* Message UID to fetch or read e.g. 100 */
int uid = imap.getUID(imap.selectedFolder().msgCount());
/** Set \Seen and \Answered to flags for message with UID
* The seesion will keep open.
*/
if (MailClient.setFlag(&imap, uid, F("\\Seen \\Answered"), false))
Serial.println("\nSetting FLAG success");
else
Serial.println("\nError, setting FLAG");
/* Add \Seen and \Answered to flags for message with UID 100 */
// MailClient.addFlag(imap, 100, "\\Seen \\Answered", false);
/* Remove \Seen and \Answered from flags for message with UID 100 */
// MailClient.removeFlag(imap, 100, "\\Seen \\Answered", false);
/* Remove Seen and Answered flags from messages using UID ranges (last 10 UIDs) */
int uid_last = imap.getUID(imap.selectedFolder().msgCount());
int uid_begin = uid_last > 10 ? uid_last - 10 : uid_last;
String sequence_set1 = String(uid_begin) + ":" + String(uid_last);
if (MailClient.removeFlag(&imap, sequence_set1, true /* if sequence set are the UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */))
Serial.println("\nRemoving FLAG with UIDs ranges success");
else
Serial.println("\nError, removing FLAG with UIDs ranges");
/* Remove Seen and Answered flags from messages using message sequence ranges (last 10 message numbers) */
int msg_last = imap.selectedFolder().msgCount();
int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last;
String sequence_set2 = String(msg_begin) + ":" + String(msg_last);
if (MailClient.removeFlag(&imap, sequence_set2, false /* if sequence set are message numbers not UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */))
Serial.println("\nRemoving FLAG with message numbers ranges success");
else
Serial.println("\nError, removing FLAG with message numbers ranges");
imap_data.fetch.uid = uid;
/* Read or search the Email and close the session */
MailClient.readMail(&imap);
/* Clear all stored data in IMAPSession object */
imap.empty();
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}

View File

@ -0,0 +1,309 @@
/**
* This example shows how to set messages flags.
*
* Email: suwatchai@outlook.com
*
* Github: https://github.com/mobizt/ESP-Mail-Client
*
* Copyright (c) 2023 mobizt
*
*/
// This example shows how to set messages flags using message numbers ranges.
/** Note for library update from v2.x.x to v3.x.x.
*
* Struct data names changed
*
* "ESP_Mail_Session" changes to "Session_Config"
* "IMAP_Config" changes to "IMAP_Data"
*
* Changes in the examples
*
* ESP_Mail_Session session;
* to
* Session_Config config;
*
* IMAP_Config config;
* to
* IMAP_Data imap_data;
*/
/** For ESP8266, with BearSSL WiFi Client
* The memory reserved for completed valid SSL response from IMAP is 16 kbytes which
* may cause your device out of memory reset in case the memory
* allocation error.
*/
#include <Arduino.h>
#if defined(ESP32) || defined(ARDUINO_RASPBERRY_PI_PICO_W)
#include <WiFi.h>
#elif defined(ESP8266)
#include <ESP8266WiFi.h>
#elif __has_include(<WiFiNINA.h>)
#include <WiFiNINA.h>
#elif __has_include(<WiFi101.h>)
#include <WiFi101.h>
#elif __has_include(<WiFiS3.h>)
#include <WiFiS3.h>
#endif
#include <ESP_Mail_Client.h>
#define WIFI_SSID "<ssid>"
#define WIFI_PASSWORD "<password>"
/** For Gmail, IMAP option should be enabled. https://support.google.com/mail/answer/7126229?hl=en
* and also https://accounts.google.com/b/0/DisplayUnlockCaptcha
*
* Some Gmail user still not able to sign in using account password even above options were set up,
* for this case, use "App Password" to sign in instead.
* About Gmail "App Password", go to https://support.google.com/accounts/answer/185833?hl=en
*
* For Yahoo mail, log in to your yahoo mail in web browser and generate app password by go to
* https://login.yahoo.com/account/security/app-passwords/add/confirm?src=noSrc
*
* To use Gmai and Yahoo's App Password to sign in, define the AUTHOR_PASSWORD with your App Password
* and AUTHOR_EMAIL with your account email.
*/
/* The imap host name e.g. imap.gmail.com for GMail or outlook.office365.com for Outlook */
#define IMAP_HOST "<host>"
/** The imap port e.g.
* 143 or esp_mail_imap_port_143
* 993 or esp_mail_imap_port_993
*/
#define IMAP_PORT 993
/* The log in credentials */
#define AUTHOR_EMAIL "<email>"
#define AUTHOR_PASSWORD "<password>"
/* Print the list of mailbox folders */
void printAllMailboxesInfo(IMAPSession &imap);
/* Print the selected folder info */
void printSelectedMailboxInfo(SelectedFolderInfo sFolder);
/* Declare the global used IMAPSession object for IMAP transport */
IMAPSession imap;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
WiFiMulti multi;
#endif
void setup()
{
Serial.begin(115200);
#if defined(ARDUINO_ARCH_SAMD)
while (!Serial)
;
#endif
Serial.println();
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
multi.addAP(WIFI_SSID, WIFI_PASSWORD);
multi.run();
#else
WiFi.begin(WIFI_SSID, WIFI_PASSWORD);
#endif
Serial.print("Connecting to Wi-Fi");
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
unsigned long ms = millis();
#endif
while (WiFi.status() != WL_CONNECTED)
{
Serial.print(".");
delay(300);
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
if (millis() - ms > 10000)
break;
#endif
}
Serial.println();
Serial.print("Connected with IP: ");
Serial.println(WiFi.localIP());
Serial.println();
/* Set the network reconnection option */
MailClient.networkReconnect(true);
// The WiFi credentials are required for Pico W
// due to it does not have reconnect feature.
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
MailClient.clearAP();
MailClient.addAP(WIFI_SSID, WIFI_PASSWORD);
#endif
/** Enable the debug via Serial port
* 0 for no debugging
* 1 for basic level debugging
*
* Debug port can be changed via ESP_MAIL_DEFAULT_DEBUG_PORT in ESP_Mail_FS.h
*/
imap.debug(1);
/** In case the SD card/adapter was used for the file storagge, the SPI pins can be configure from
* MailClient.sdBegin function which may be different for ESP32 and ESP8266
* For ESP32, assign all of SPI pins
* MailClient.sdBegin(14,2,15,13)
* Which SCK = 14, MISO = 2, MOSI = 15 and SS = 13
* And for ESP8266, assign the CS pins of SPI port
* MailClient.sdBegin(15)
* Which pin 15 is the CS pin of SD card adapter
*/
/* Declare the Session_Config for user defined session credentials */
Session_Config config;
/* Set the session config */
config.server.host_name = IMAP_HOST;
config.server.port = IMAP_PORT;
config.login.email = AUTHOR_EMAIL;
config.login.password = AUTHOR_PASSWORD;
/* Define the IMAP_Data object used for user defined IMAP operating options. */
IMAP_Data imap_data;
/* Set seen flag */
// imap_data.fetch.set_seen = true;
/* Search criteria */
imap_data.search.criteria.clear();
/* Also search the unseen message */
imap_data.search.unseen_msg = true;
/* Set the storage to save the downloaded files and attachments */
imap_data.storage.saved_path = F("/email_data");
/** The file storage type e.g.
* esp_mail_file_storage_type_none,
* esp_mail_file_storage_type_flash, and
* esp_mail_file_storage_type_sd
*/
imap_data.storage.type = esp_mail_file_storage_type_flash;
/** Set to download headers, text and html messaeges,
* attachments and inline images respectively.
*/
imap_data.download.header = true;
imap_data.download.text = true;
imap_data.download.html = true;
imap_data.download.attachment = true;
imap_data.download.inlineImg = true;
/** Set to enable the results i.e. html and text messaeges
* which the content stored in the IMAPSession object is limited
* by the option imap_data.limit.msg_size.
* The whole message can be download through imap_data.download.text
* or imap_data.download.html which not depends on these enable options.
*/
imap_data.enable.html = true;
imap_data.enable.text = true;
/* Set to enable the sort the result by message UID in the decending order */
imap_data.enable.recent_sort = true;
/* Set to report the download progress via the default serial port */
imap_data.enable.download_status = true;
/* Set the limit of number of messages in the search results */
imap_data.limit.search = 5;
/** Set the maximum size of message stored in
* IMAPSession object in byte
*/
imap_data.limit.msg_size = 512;
/** Set the maximum attachments and inline images files size
* that can be downloaded in byte.
* The file which its size is largger than this limit may be saved
* as truncated file.
*/
imap_data.limit.attachment_size = 1024 * 1024 * 5;
/* Connect to the server */
if (!imap.connect(&config, &imap_data))
return;
/* {Optional} */
printAllMailboxesInfo(imap);
/* Open or select the mailbox folder to read or search the message */
if (!imap.selectFolder(F("INBOX")))
return;
/* {Optional} */
printSelectedMailboxInfo(imap.selectedFolder());
/* Add Seen and Answered flags from messages using message numbers ranges (last 10 message numbers) */
int msg_last = imap.selectedFolder().msgCount();
int msg_begin = msg_last > 10 ? msg_last - 10 : msg_last;
String sequence_set1 = String(msg_begin) + ":" + String(msg_last);
if (MailClient.addFlag(&imap, sequence_set1, false /* if sequence set are message numbers not UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */))
Serial.println("\nAdding FLAG with message numbers ranges success");
else
Serial.println("\nError, adding FLAG with message numbers ranges");
/* Remove Seen and Answered flags from messages using message numbers ranges (last 10 message numbers) */
if (MailClient.removeFlag(&imap, sequence_set1, false /* if sequence set are message numbers not UIDs */, F("\\Seen \\Answered"), false /* Close session */, false /* Ignore response */))
Serial.println("\nRemoving FLAG with message numbers ranges success");
else
Serial.println("\nError, removing FLAG with message numbers ranges");
MailClient.printf("Free Heap: %d\n", MailClient.getFreeHeap());
}
void loop()
{
}
void printAllMailboxesInfo(IMAPSession &imap)
{
/* Declare the folder collection class to get the list of mailbox folders */
FoldersCollection folders;
/* Get the mailbox folders */
if (imap.getFolders(folders))
{
for (size_t i = 0; i < folders.size(); i++)
{
/* Iterate each folder info using the folder info item data */
FolderInfo folderInfo = folders.info(i);
MailClient.printf("%s%s%s", i == 0 ? "\nAvailable folders: " : ", ", folderInfo.name, i == folders.size() - 1 ? "\n" : "");
}
}
}
void printSelectedMailboxInfo(SelectedFolderInfo sFolder)
{
/* Show the mailbox info */
MailClient.printf("\nInfo of the selected folder\nTotal Messages: %d\n", sFolder.msgCount());
MailClient.printf("UID Validity: %d\n", sFolder.uidValidity());
MailClient.printf("Predicted next UID: %d\n", sFolder.nextUID());
if (sFolder.unseenIndex() > 0)
MailClient.printf("First Unseen Message Number: %d\n", sFolder.unseenIndex());
else
MailClient.printf("Unseen Messages: No\n");
if (sFolder.modSeqSupported())
MailClient.printf("Highest Modification Sequence: %llu\n", sFolder.highestModSeq());
for (size_t i = 0; i < sFolder.flagCount(); i++)
MailClient.printf("%s%s%s", i == 0 ? "Flags: " : ", ", sFolder.flag(i).c_str(), i == sFolder.flagCount() - 1 ? "\n" : "");
if (sFolder.flagCount(true))
{
for (size_t i = 0; i < sFolder.flagCount(true); i++)
MailClient.printf("%s%s%s", i == 0 ? "Permanent Flags: " : ", ", sFolder.flag(i, true).c_str(), i == sFolder.flagCount(true) - 1 ? "\n" : "");
}
}

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