Merge branch 'development' into prerelease-13.2
This commit is contained in:
commit
2d97311c5c
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -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**_
|
||||
|
||||
4
.github/workflows/Tasmota_build_devel.yml
vendored
4
.github/workflows/Tasmota_build_devel.yml
vendored
@ -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
|
||||
|
||||
4
.github/workflows/Tasmota_build_master.yml
vendored
4
.github/workflows/Tasmota_build_master.yml
vendored
@ -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
|
||||
|
||||
4
.github/workflows/build_all_the_things.yml
vendored
4
.github/workflows/build_all_the_things.yml
vendored
@ -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
1
.gitignore
vendored
@ -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
|
||||
|
||||
|
||||
@ -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 | - | - / - | - | - | - | - |
|
||||
|
||||
87
CHANGELOG.md
87
CHANGELOG.md
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
106
RELEASENOTES.md
106
RELEASENOTES.md
@ -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)
|
||||
|
||||
17
TEMPLATES.md
17
TEMPLATES.md
@ -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
44
boards/esp32c2.json
Normal 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
44
boards/esp32c2_2M.json
Normal 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"
|
||||
}
|
||||
@ -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
45
boards/esp32c6cdc.json
Normal 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"
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -53,7 +53,7 @@
|
||||
*/
|
||||
|
||||
#include "Arduino.h"
|
||||
#include <EEPROM.h>
|
||||
//#include <EEPROM.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <ESP8266WebServer.h>
|
||||
|
||||
@ -19,5 +19,9 @@
|
||||
"frameworks": "Arduino",
|
||||
"examples": [
|
||||
"examples/*/*.ino"
|
||||
]
|
||||
],
|
||||
"build": {
|
||||
"includeDir": ".",
|
||||
"flags": [ "-Wno-stringop-overread" ]
|
||||
}
|
||||
}
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
27
lib/lib_audio/ESP8266Audio/tasmota_patches.txt
Normal file
27
lib/lib_audio/ESP8266Audio/tasmota_patches.txt
Normal 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'
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -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"
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
{
|
||||
|
||||
892
lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h
Normal file
892
lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32RmtMethod_idf5.h
Normal 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(©_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
|
||||
504
lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h
Normal file
504
lib/lib_basic/NeoPixelBus/src/internal/NeoEsp32SpiMethod_idf5.h
Normal 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
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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))
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
||||
|
||||
@ -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 )
|
||||
|
||||
@ -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?
|
||||
|
||||
@ -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
|
||||
38
lib/lib_i2c/ScioSense_ENS16x/README.md
Normal file
38
lib/lib_i2c/ScioSense_ENS16x/README.md
Normal 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
|
||||
65
lib/lib_i2c/ScioSense_ENS16x/keywords.txt
Normal file
65
lib/lib_i2c/ScioSense_ENS16x/keywords.txt
Normal 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
|
||||
9
lib/lib_i2c/ScioSense_ENS16x/library.properties
Normal file
9
lib/lib_i2c/ScioSense_ENS16x/library.properties
Normal 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=*
|
||||
490
lib/lib_i2c/ScioSense_ENS16x/src/ScioSense_ENS16x.cpp
Normal file
490
lib/lib_i2c/ScioSense_ENS16x/src/ScioSense_ENS16x.cpp
Normal 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;
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
212
lib/lib_i2c/ScioSense_ENS16x/src/ScioSense_ENS16x.h
Normal file
212
lib/lib_i2c/ScioSense_ENS16x/src/ScioSense_ENS16x.h
Normal 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
|
||||
28
lib/lib_i2c/ScioSense_ENS210/README.md
Normal file
28
lib/lib_i2c/ScioSense_ENS210/README.md
Normal 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.
|
||||
53
lib/lib_i2c/ScioSense_ENS210/keywords.txt
Normal file
53
lib/lib_i2c/ScioSense_ENS210/keywords.txt
Normal 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
|
||||
9
lib/lib_i2c/ScioSense_ENS210/library.properties
Normal file
9
lib/lib_i2c/ScioSense_ENS210/library.properties
Normal 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=*
|
||||
648
lib/lib_i2c/ScioSense_ENS210/src/ScioSense_ENS210.cpp
Normal file
648
lib/lib_i2c/ScioSense_ENS210/src/ScioSense_ENS210.cpp
Normal 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;
|
||||
}
|
||||
|
||||
149
lib/lib_i2c/ScioSense_ENS210/src/ScioSense_ENS210.h
Normal file
149
lib/lib_i2c/ScioSense_ENS210/src/ScioSense_ENS210.h
Normal 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
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -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];
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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.
|
||||
1127
lib/libesp32/ESP-Mail-Client/README.md
Normal file
1127
lib/libesp32/ESP-Mail-Client/README.md
Normal file
File diff suppressed because it is too large
Load Diff
258
lib/libesp32/ESP-Mail-Client/examples/IMAP/ACL/ACL.ino
Normal file
258
lib/libesp32/ESP-Mail-Client/examples/IMAP/ACL/ACL.ino
Normal 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()
|
||||
{
|
||||
}
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
@ -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.
|
||||
*/
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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(ð_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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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", "a_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()
|
||||
{
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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()
|
||||
{
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
@ -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" : "");
|
||||
}
|
||||
}
|
||||
@ -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
Loading…
Reference in New Issue
Block a user