172 Commits

Author SHA1 Message Date
eeeck 03adefeee7 Minor fixes in EDA 2026-03-13 15:15:02 +01:00
eeeck 60d7752721 Change log types 2025-12-13 13:08:38 +01:00
eeeck 514f4d5d69 Add delay and log 2025-12-13 12:53:08 +01:00
eeeck d8a29c30d4 Correct build info 2025-12-13 12:43:14 +01:00
eeeck b108d57c12 Add new definition for I2C commands 2025-12-13 12:42:53 +01:00
eeeck af8e330460 Add definition for default slave address 2025-12-13 12:42:36 +01:00
eeeck 46fcb137b4 Add includes 2025-12-13 12:42:23 +01:00
eeeck 2a3eaf2acc Fix task handle name and stack overflow issue 2025-12-13 12:42:05 +01:00
eeeck 3d841230bf Fix include 2025-12-13 12:41:46 +01:00
eeeck 26bbe5b518 Send packet when notified from MQTT 2025-12-13 12:41:38 +01:00
eeeck 68e5a67fb7 Implement new function to send packet via I2C/TWI 2025-12-13 12:41:12 +01:00
eeeck 50fbe9e9eb Add a second slave for testing 2025-12-13 12:40:39 +01:00
eeeck 5dff5da328 Fix initialization of master 2025-12-13 12:40:22 +01:00
eeeck 72974c41a7 Configure multiple slave management 2025-12-13 12:40:00 +01:00
eeeck 9fab98af61 Add includes 2025-12-13 12:39:33 +01:00
eeeck aba6253e70 Add delay and log 2025-12-13 12:39:16 +01:00
eeeck 6bfdc19fa8 Implement parsing method for MQTT messages 2025-12-13 12:39:04 +01:00
eeeck 184a0eed27 Remove port as per new Espressif MQTT lib 2025-12-13 12:38:41 +01:00
eeeck 1bbd73ff49 Buffering implementation with local buffer 2025-12-13 12:38:21 +01:00
eeeck cd36415807 Subscribe to topics 2025-12-13 12:37:51 +01:00
eeeck dc5c2c751b Change message receive implementation to allow for only one action at a
time
2025-12-13 12:36:15 +01:00
eeeck 137814206c It's a plant thing! 2025-12-13 12:32:03 +01:00
eeeck 2b8bbd703b Fix indentation 2025-12-13 12:31:24 +01:00
eeeck 1c21ddee89 Add #pragma once to ESP32 headers 2025-12-13 12:30:49 +01:00
eeeck 14fc015d1b Wait for Wi‑Fi and MQTT before I2C read 2025-12-12 14:08:09 +01:00
eeeck b9c8a5d2a7 Change logs from informative to verbose 2025-12-10 23:09:11 +01:00
eeeck f961cc62a0 Move definition to config 2025-12-10 23:09:06 +01:00
eeeck 0d0750b746 Merge branch 'dev-esp32-mqtt' into dev-twi 2025-12-10 09:41:41 +01:00
eeeck 626bbe9dbb Remove task handle: managed in dev-twi main.cpp 2025-12-10 00:27:30 +01:00
eeeck 63c358fd87 Add task handle for task notifications 2025-12-10 00:24:44 +01:00
eeeck 1a893547b6 Finalize event groups to improve performance 2025-12-09 23:50:26 +01:00
eeeck 06a672d1f7 Remove old code about I2C 2025-12-09 23:40:53 +01:00
eeeck b1a6dfddd3 Wait for Wi-Fi connection before initializing MQTT 2025-12-09 23:23:10 +01:00
eeeck 2e6e829829 Only clear Wi-Fi bit 2025-12-09 23:22:35 +01:00
eeeck 6a2a933002 Better wait implementation with no spinlock from MQTT task 2025-12-09 23:02:21 +01:00
eeeck aa395c381b Remove redundant log 2025-12-09 10:49:32 +01:00
eeeck eaad4469bc Normalize spacing in ESP32 firmware 2025-12-09 10:04:06 +01:00
eeeck 4e78a5f2ed Go in critical error if MQTT is not being initialized 2025-12-09 10:03:06 +01:00
eeeck c53783072e Set MQTT username and password 2025-12-09 10:02:47 +01:00
eeeck 9bad1790a7 Log MQTT errors 2025-12-09 10:02:29 +01:00
eeeck 4cd9a3210c Comment out I2C task handles 2025-12-09 10:01:54 +01:00
eeeck 2c7951c2bb Fix missing code from merge for connectivity_event_group 2025-12-09 01:37:18 +01:00
eeeck 88c7635ed9 Merge branch 'dev-esp32-wifi' into dev-esp32-mqtt 2025-12-09 01:00:26 +01:00
eeeck b0059f6e9f Move user configuration to config.h 2025-12-09 00:24:36 +01:00
eeeck 985642e0fe Fix compilation issues with espressif mqtt lib 2025-12-04 23:00:46 +01:00
eeeck fb98ce800a Add network speed check for future use 2025-12-04 21:51:16 +01:00
eeeck a332c37e72 Replace polling it with a blocking wait on connectivity flag and
notification
2025-12-04 21:51:02 +01:00
eeeck 567fca2916 Tweak logs 2025-12-01 00:55:59 +01:00
eeeck 04b5fb0a7c Fix task event notification 2025-12-01 00:54:00 +01:00
eeeck 6fd2d2523d Add global event group handle for connectivity 2025-12-01 00:53:12 +01:00
eeeck 9143bd0f76 Add MQTT checks 2025-12-01 00:18:39 +01:00
eeeck c6c4011a47 Fix vTaskDelay syntax error 2025-11-30 23:48:08 +01:00
eeeck 213f6b399f Changed some logs type from informative to debug 2025-11-30 23:40:59 +01:00
eeeck 0a418805a4 Changed some logs type from informative to verbose 2025-11-30 23:40:24 +01:00
eeeck 3670b58f8e Implement task handle for managing I2C 2025-11-30 23:36:54 +01:00
eeeck 5dd2c00ac0 Parametrize task delay values 2025-11-30 23:36:27 +01:00
eeeck 2fcc3172aa Fix message logs for consistency with codebase 2025-11-30 22:24:33 +01:00
eeeck 665125e07f Implement MQTT event groups 2025-11-30 22:24:09 +01:00
eeeck 401c610a58 Create shared event group 2025-11-30 22:22:26 +01:00
eeeck 1ef2476f78 MQTT initialization 2025-11-30 17:40:54 +01:00
eeeck 28ac3f44b3 Fix task delay duration 2025-11-29 14:16:11 +01:00
eeeck 29ad9350a3 Fix task name 2025-11-29 14:15:17 +01:00
eeeck 455ab94449 Add TODO 2025-11-29 14:13:28 +01:00
eeeck 49cf49db87 Create boilerplate for task
- To change even group - To create i2c_read and i2c_write functions
2025-11-29 14:13:18 +01:00
eeeck 50dd39fd60 Add task log 2025-11-29 14:04:38 +01:00
eeeck a02d3e3294 Add build instructions for I2C 2025-11-27 15:55:42 +01:00
eeeck 3a91791180 Fix TWI address reading error 2025-11-27 15:55:29 +01:00
eeeck 71106c2542 Add I2C task 2025-11-27 15:54:57 +01:00
eeeck 4f0dd9faaa Add TWI (I2C) init for ESP32 2025-11-27 15:54:40 +01:00
eeeck cd4d2658b9 Initialize MQTT task 2025-11-06 19:19:52 +01:00
eeeck a1781af096 Merge branch 'main' into dev-twi 2025-11-06 17:00:06 +01:00
eeeck 92e0bcc2f5 Merge branch 'dev-esp32-wifi' 2025-11-06 16:19:08 +01:00
eeeck 4653fe05cb Refactor Wi-Fi connection logic to improve stability, simplify event
handling, and enhance logging and watchdog reliability.
2025-11-06 16:16:38 +01:00
eeeck c74a0501c1 Move esp_netif_create_default_wifi_sta() before initializing Wi-Fi to
align with the ESP-IDF recommended order
2025-11-06 13:22:46 +01:00
eeeck 8e82e21a3d Re-implement Wi-Fi retry limiter by using a maximum timeout tick 2025-11-05 22:06:40 +01:00
eeeck e9c22810a4 Implement Wi-Fi connection max retry limit after connection is lost 2025-11-05 14:42:13 +01:00
eeeck 8e96b0ef37 Restructure loop and remove if branch: it would either always trigger it
or reboot

-
2025-10-30 15:05:39 +01:00
eeeck 1053515ced Remove hardcoded tag from logs 2025-10-30 10:19:53 +01:00
eeeck 91cc34a33e Change log types 2025-10-29 15:34:19 +01:00
eeeck 2be65a0b76 Implement plant watering based on current moisture levels 2025-10-29 14:45:40 +01:00
eeeck 620eb57920 Reorder respond cases for better clarity 2025-10-29 14:44:50 +01:00
eeeck b28b20f46a Refactor TWI response system
- Avoid setting respondFlag in main, instead let it be managed directly
inside twiListen() and read inside twiRespond()
2025-10-29 14:30:23 +01:00
eeeck 1721be5e66 Remove triggerMoistureRead() call in ISR and it's trigger variable
- This was done at the very beginning when i thought to develop this
part of the program in a different way. It is unnecessary with how I
actually ended up to structure the program. - WDT should manage TWI
only, as per current developement
2025-10-29 13:51:04 +01:00
eeeck b0a765d0cc Remove old log 2025-10-24 23:36:22 +02:00
eeeck c3766d4e14 Fix STA initialization order 2025-10-24 23:36:15 +02:00
eeeck e20c90a021 Change define names 2025-10-24 22:54:46 +02:00
eeeck cb708d72f7 Create Wi-Fi task 2025-10-24 22:54:13 +02:00
eeeck e986120e66 Fix Wi-Fi config assignment error 2025-10-24 22:48:57 +02:00
eeeck 12be9a6141 Add watchdog library 2025-10-24 22:47:06 +02:00
eeeck 1c7cf84ece Fix designated initializer issue 2025-10-24 22:23:34 +02:00
eeeck a7385654f4 Refactor Wi-Fi task to use event groups 2025-10-24 22:22:40 +02:00
eeeck b54d3c744c Update libraries 2025-10-24 22:04:04 +02:00
eeeck 6582872ed0 Refactor Wi-Fi initialization and connection with event groups 2025-10-24 21:55:47 +02:00
eeeck 969fda6ad4 Refactor wifi initialization with event groups 2025-10-24 21:04:32 +02:00
eeeck 1aa2ebbadc Define event group 2025-10-24 20:39:52 +02:00
eeeck be7234f621 Add logs 2025-10-15 13:38:51 +02:00
eeeck eb897dca9e Reinitialize WDT at runtime
- This is needed because of some issues when compiling without using
menuconfig. Maybe there is a way to do this modifying sdkconfig.defaults
when still inside Docker
2025-10-15 13:38:05 +02:00
eeeck d49c69f647 Add error check 2025-10-14 23:32:27 +02:00
eeeck ebee1553ae Increase max frequency to match ESP32-C3 processor 2025-10-14 23:31:13 +02:00
eeeck 60c6a19f13 FIx build script with correct implementation for flashing firmware 2025-10-14 23:29:02 +02:00
eeeck 2a36d1356c Move TWI response handling from watchdog to main loop 2025-10-12 21:45:01 +02:00
eeeck fafd6a9a7a Directory restructure 2025-10-12 20:39:51 +02:00
eeeck 0f0408df9b Simplify moisture value access and update header structure 2025-10-12 14:27:15 +02:00
eeeck 2b86ff133c Remove trailing whitespace 2025-10-12 13:53:39 +02:00
eeeck a1f687e644 Add wifi-credentials.h with SSID, password and auth defines 2025-10-12 00:58:59 +02:00
eeeck 6f37e0d420 Add volatile to include 2025-10-12 00:54:08 +02:00
eeeck fcff8f9900 Add License 2025-10-12 00:33:33 +02:00
eeeck 4be663e688 Update build script to use modern esptool and correct firmware paths 2025-10-11 23:46:57 +02:00
eeeck 95ee47386d Fix WiFi configuration initialization and add proper logging 2025-10-11 23:46:47 +02:00
eeeck c0758b071e Fix power management API and variable naming for ESP32-C3 compatibility 2025-10-11 23:46:33 +02:00
eeeck 4a9a3ef805 Add ESP-IDF component configuration for main directory 2025-10-11 23:46:23 +02:00
eeeck ed7fb9fda6 Fix ESP32-C3 target configuration in Dockerfile 2025-10-11 23:46:12 +02:00
eeeck 558413df41 Add WiFi connectivity initialization and configuration functions 2025-10-11 20:17:57 +02:00
eeeck 94d2a61cad Implement Wi-Fi task 2025-10-11 15:30:40 +02:00
eeeck eb980d286d Fix watchdog initialization and parameters 2025-10-11 14:15:06 +02:00
eeeck 55c11f2471 Add CMakeLists.txt for ESP32 firmware build 2025-10-11 13:08:10 +02:00
eeeck ba590b982c Fix build error in Dockerfile 2025-10-11 00:05:15 +02:00
eeeck d1cf04ffdb Allocate heap caps 2025-10-10 23:59:50 +02:00
eeeck 3dc234eecb Configure power management 2025-10-10 23:59:39 +02:00
eeeck 3d8962b188 Initialize basic watchdog 2025-10-10 23:59:14 +02:00
eeeck 9f848dcc3f Add Dockerfile and build script for ESP32 firmware 2025-10-10 22:30:32 +02:00
eeeck 2d9a4f3bb5 Fix TWI slave address shift and buffer index 2025-10-09 11:04:16 +02:00
eeeck 618965ccc2 Rename Makefile project name to same name as repository 2025-10-05 23:57:03 +02:00
eeeck d7364a6fdc Make triggerMoistureRead function inline 2025-10-05 23:56:41 +02:00
eeeck 2d6643601d Implement TWI response method 2025-10-05 23:52:09 +02:00
eeeck 74aab766fc Add read-only pointer accessor for previously read moisture value 2025-10-05 22:21:21 +02:00
eeeck 6c48ebb65f Add data receiving capabilities using a buffer with overflow protection 2025-10-05 17:38:49 +02:00
eeeck 443c62593d Add EEPROM flush function to clear address contents 2025-10-04 14:37:38 +02:00
eeeck 40a5ad5a35 Add TWI module to build sources 2025-10-01 16:18:37 +02:00
eeeck c24e032981 Add FreeRTOS and GPIO includes 2025-10-01 15:40:05 +02:00
eeeck fb3fdab7df Fix error in comment 2025-10-01 15:39:52 +02:00
eeeck f4e690cf3c Increase EEPROM lifespan by avoiding overwrites on addresses that
contain identical values
2025-10-01 15:34:11 +02:00
eeeck c60493810c Improve EEPROM handling 2025-10-01 15:32:02 +02:00
eeeck fb8423cd9a Clarify inline function name 2025-10-01 01:40:32 +02:00
eeeck 45464300c7 Correct bitmask for TWI SDA and SCL 2025-10-01 01:39:53 +02:00
eeeck 05aae91d12 Mark internal helpers as static and remove from headers 2025-10-01 01:25:59 +02:00
eeeck 6e845c65da Write configuration values to EEPROM at boot 2025-10-01 01:06:20 +02:00
eeeck 2e6fe9ba6b Implement AVR328 EEPROM handling 2025-10-01 00:08:25 +02:00
eeeck 5cce419c74 Add initial ESP32 main.cpp 2025-05-19 11:41:22 +02:00
eeeck 135823b620 Improve atmega Dockerfile apt handling
- Set DEBIAN_FRONTEND as an environment variable.
- Add --no-install-recommends to apt-get install.
2025-05-19 11:39:07 +02:00
eeeck ff8f6324e5 Use deeper sleep mode to reduce current draw during idle
Using `SLEEP_MODE_PWR_DOWN` turns off everything (I/O, clocks, ADC etc.) except the  watchdog
2025-05-19 11:37:12 +02:00
eeeck 29ecd9be17 Fix return non-zero value in main 2025-05-19 11:34:35 +02:00
eeeck 24c454aa88 Reset readSensors before sleep 2025-05-17 14:28:55 +02:00
eeeck 97d78f7c28 Remove unsed flag 2025-05-17 14:23:56 +02:00
eeeck 2a2cb42b0b Refactor optimization flag in Makefile
Introduce `O_FLAG` variable for `-Os` to centralize optimization setting
for CFLAGS and LDFLAGS.
2025-05-17 14:23:22 +02:00
eeeck 906dfa91f0 Remove unused CMD from Dockerfile 2025-05-17 14:22:58 +02:00
eeeck c03e60e56f Add delay to let actuator pump water 2025-05-17 14:07:45 +02:00
eeeck c7abf18736 Change data types regarding sensor readings and sensor/actuator pins from signed to unsigned 2025-05-17 13:49:37 +02:00
eeeck d6bd1932d3 Make pumps initialization and actuation more dynamic by checking which one are declared in config.h 2025-05-17 13:10:45 +02:00
eeeck 8ad766c377 Make sensor initialization and measurement more dynamic by checking
which one are declared in config.h
2025-05-17 12:56:22 +02:00
eeeck ba10840f50 Rename function 2025-05-16 09:22:34 +02:00
eeeck 64852b2a67 Add pump code to Makefile 2025-05-16 09:22:20 +02:00
eeeck 09fed73696 Add waterPlant stub and update pump usage 2025-05-15 23:39:15 +02:00
eeeck c8c27d440c Implement pump control via port register 2025-05-15 23:30:48 +02:00
eeeck 3973d7b41d Initialize pumps' digital pins 2025-05-15 22:41:14 +02:00
eeeck cf3230c470 Rename functions name for better code clarity 2025-05-15 22:40:33 +02:00
eeeck 412354fe88 Move source code to /firmware and fix build paths 2025-05-15 15:51:46 +02:00
eeeck 6dd4b87a0f Simplify Makefile to exclude Arduino core libraries
- Binary file is now <700 bytes, from ~5500 bytes when using Arduino
libraries and core sources
- Time to flash to MCU is decreased from ~8s to ~0.75s
- Change target object name for better clarity
2025-05-15 11:06:51 +02:00
eeeck fe2e04ee38 Implement multiple sensors reading for moisture 2025-05-15 00:32:00 +02:00
eeeck 1a10abc4d6 Use custom ADC interface using AVR flags 2025-05-14 22:38:32 +02:00
eeeck cbf42aae0a Remove make flash, use build script for flashing
This is not optimal, but could not find a way to make it flash without
verification errors with "make flash".
2025-05-14 14:10:11 +02:00
eeeck 5f154cb20f Refactor loop to main and add explicit while(true)
This change transitions from the Arduino-specific `loop()` to a
standard C++ `main()` function as the program's entry point and
primary execution cycle.
2025-05-14 13:02:17 +02:00
eeeck 82dba30e18 Rename image name to avoid future confusion with ESP board 2025-05-13 20:12:10 +02:00
eeeck af4cb39230 Add ATmega build and flash script
Use Dockerfile for firmware compilation and avrdude for flashing
to ATmega328p via usbasp.
2025-05-13 12:42:50 +02:00
eeeck 4ab01eb3a4 Restructure directory organization 2025-05-13 11:28:18 +02:00
eeeck fff7c84206 Refactor Makefile for compatibility with Docker enviroment and better
AVR dependency management
2025-05-12 22:55:28 +02:00
eeeck 4243734056 Create Dockerfile 2025-05-12 22:54:41 +02:00
eeeck 1e7be9adb6 Restructure AVR compilation with Makefile 2025-05-12 19:24:09 +02:00
eeeck c94f7d2982 Add bootloader circuit 2025-05-04 00:34:31 +02:00
eeeck 2800986f17 Add schematics for ATMega side and initialize MCU 2025-05-03 23:46:02 +02:00
eeeck 1a7858198e Move main to C++ file 2025-05-03 12:38:05 +02:00
eeeck 04a8564d46 Merge pull request 'moisture-library' (#1) from moisture-library into main
Reviewed-on: http://192.168.2.248:3000/erickahmed/plant-manager/pulls/1
2025-05-03 12:16:00 +02:00
37 changed files with 5535 additions and 139 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Erick Ahmed
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.
+639
View File
@@ -0,0 +1,639 @@
{
"board": {
"3dviewports": [],
"design_settings": {
"defaults": {
"apply_defaults_to_fp_fields": false,
"apply_defaults_to_fp_shapes": false,
"apply_defaults_to_fp_text": false,
"board_outline_line_width": 0.05,
"copper_line_width": 0.2,
"copper_text_italic": false,
"copper_text_size_h": 1.5,
"copper_text_size_v": 1.5,
"copper_text_thickness": 0.3,
"copper_text_upright": false,
"courtyard_line_width": 0.05,
"dimension_precision": 4,
"dimension_units": 3,
"dimensions": {
"arrow_length": 1270000,
"extension_offset": 500000,
"keep_text_aligned": true,
"suppress_zeroes": true,
"text_position": 0,
"units_format": 0
},
"fab_line_width": 0.1,
"fab_text_italic": false,
"fab_text_size_h": 1.0,
"fab_text_size_v": 1.0,
"fab_text_thickness": 0.15,
"fab_text_upright": false,
"other_line_width": 0.1,
"other_text_italic": false,
"other_text_size_h": 1.0,
"other_text_size_v": 1.0,
"other_text_thickness": 0.15,
"other_text_upright": false,
"pads": {
"drill": 0.8,
"height": 1.27,
"width": 2.54
},
"silk_line_width": 0.1,
"silk_text_italic": false,
"silk_text_size_h": 1.0,
"silk_text_size_v": 1.0,
"silk_text_thickness": 0.1,
"silk_text_upright": false,
"zones": {
"min_clearance": 0.5
}
},
"diff_pair_dimensions": [],
"drc_exclusions": [],
"meta": {
"version": 2
},
"rule_severities": {
"annular_width": "error",
"clearance": "error",
"connection_width": "warning",
"copper_edge_clearance": "error",
"copper_sliver": "warning",
"courtyards_overlap": "error",
"creepage": "error",
"diff_pair_gap_out_of_range": "error",
"diff_pair_uncoupled_length_too_long": "error",
"drill_out_of_range": "error",
"duplicate_footprints": "warning",
"extra_footprint": "warning",
"footprint": "error",
"footprint_filters_mismatch": "ignore",
"footprint_symbol_mismatch": "warning",
"footprint_type_mismatch": "ignore",
"hole_clearance": "error",
"hole_to_hole": "warning",
"holes_co_located": "warning",
"invalid_outline": "error",
"isolated_copper": "warning",
"item_on_disabled_layer": "error",
"items_not_allowed": "error",
"length_out_of_range": "error",
"lib_footprint_issues": "warning",
"lib_footprint_mismatch": "warning",
"malformed_courtyard": "error",
"microvia_drill_out_of_range": "error",
"mirrored_text_on_front_layer": "warning",
"missing_courtyard": "ignore",
"missing_footprint": "warning",
"net_conflict": "warning",
"nonmirrored_text_on_back_layer": "warning",
"npth_inside_courtyard": "ignore",
"padstack": "warning",
"pth_inside_courtyard": "ignore",
"shorting_items": "error",
"silk_edge_clearance": "warning",
"silk_over_copper": "warning",
"silk_overlap": "warning",
"skew_out_of_range": "error",
"solder_mask_bridge": "error",
"starved_thermal": "error",
"text_height": "warning",
"text_on_edge_cuts": "error",
"text_thickness": "warning",
"through_hole_pad_without_hole": "error",
"too_many_vias": "error",
"track_angle": "error",
"track_dangling": "warning",
"track_segment_length": "error",
"track_width": "error",
"tracks_crossing": "error",
"unconnected_items": "error",
"unresolved_variable": "error",
"via_dangling": "warning",
"zones_intersect": "error"
},
"rules": {
"max_error": 0.005,
"min_clearance": 0.0,
"min_connection": 0.0,
"min_copper_edge_clearance": 0.5,
"min_groove_width": 0.0,
"min_hole_clearance": 0.25,
"min_hole_to_hole": 0.25,
"min_microvia_diameter": 0.2,
"min_microvia_drill": 0.1,
"min_resolved_spokes": 2,
"min_silk_clearance": 0.0,
"min_text_height": 0.8,
"min_text_thickness": 0.08,
"min_through_hole_diameter": 0.3,
"min_track_width": 0.0,
"min_via_annular_width": 0.1,
"min_via_diameter": 0.5,
"solder_mask_to_copper_clearance": 0.0,
"use_height_for_length_calcs": true
},
"teardrop_options": [
{
"td_onpthpad": true,
"td_onroundshapesonly": false,
"td_onsmdpad": true,
"td_ontrackend": false,
"td_onvia": true
}
],
"teardrop_parameters": [
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_round_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_rect_shape",
"td_width_to_size_filter_ratio": 0.9
},
{
"td_allow_use_two_tracks": true,
"td_curve_segcount": 0,
"td_height_ratio": 1.0,
"td_length_ratio": 0.5,
"td_maxheight": 2.0,
"td_maxlen": 1.0,
"td_on_pad_in_zone": false,
"td_target_name": "td_track_end",
"td_width_to_size_filter_ratio": 0.9
}
],
"track_widths": [],
"tuning_pattern_settings": {
"diff_pair_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 1.0
},
"diff_pair_skew_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
},
"single_track_defaults": {
"corner_radius_percentage": 80,
"corner_style": 1,
"max_amplitude": 1.0,
"min_amplitude": 0.2,
"single_sided": false,
"spacing": 0.6
}
},
"via_dimensions": [],
"zones_allow_external_fillets": false
},
"ipc2581": {
"dist": "",
"distpn": "",
"internal_id": "",
"mfg": "",
"mpn": ""
},
"layer_pairs": [],
"layer_presets": [],
"viewports": []
},
"boards": [],
"cvpcb": {
"equivalence_files": []
},
"erc": {
"erc_exclusions": [],
"meta": {
"version": 0
},
"pin_map": [
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
1,
0,
1,
2
],
[
0,
1,
0,
0,
0,
0,
1,
1,
2,
1,
1,
2
],
[
0,
0,
0,
0,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
2
],
[
1,
1,
1,
1,
1,
0,
1,
1,
1,
1,
1,
2
],
[
0,
0,
0,
1,
0,
0,
1,
0,
0,
0,
0,
2
],
[
0,
2,
1,
2,
0,
0,
1,
0,
2,
2,
2,
2
],
[
0,
2,
0,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
0,
2,
1,
1,
0,
0,
1,
0,
2,
0,
0,
2
],
[
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2,
2
]
],
"rule_severities": {
"bus_definition_conflict": "error",
"bus_entry_needed": "error",
"bus_to_bus_conflict": "error",
"bus_to_net_conflict": "error",
"different_unit_footprint": "error",
"different_unit_net": "error",
"duplicate_reference": "error",
"duplicate_sheet_names": "error",
"endpoint_off_grid": "warning",
"extra_units": "error",
"footprint_filter": "ignore",
"footprint_link_issues": "warning",
"four_way_junction": "ignore",
"global_label_dangling": "warning",
"hier_label_mismatch": "error",
"label_dangling": "error",
"label_multiple_wires": "warning",
"lib_symbol_issues": "warning",
"lib_symbol_mismatch": "warning",
"missing_bidi_pin": "warning",
"missing_input_pin": "warning",
"missing_power_pin": "error",
"missing_unit": "warning",
"multiple_net_names": "warning",
"net_not_bus_member": "warning",
"no_connect_connected": "warning",
"no_connect_dangling": "warning",
"pin_not_connected": "error",
"pin_not_driven": "error",
"pin_to_pin": "warning",
"power_pin_not_driven": "error",
"same_local_global_label": "warning",
"similar_label_and_power": "warning",
"similar_labels": "warning",
"similar_power": "warning",
"simulation_model_issue": "ignore",
"single_global_label": "ignore",
"unannotated": "error",
"unconnected_wire_endpoint": "warning",
"undefined_netclass": "error",
"unit_value_mismatch": "error",
"unresolved_variable": "error",
"wire_dangling": "error"
}
},
"libraries": {
"pinned_footprint_libs": [],
"pinned_symbol_libs": []
},
"meta": {
"filename": "atmega.kicad_pro",
"version": 3
},
"net_settings": {
"classes": [
{
"bus_width": 12,
"clearance": 0.2,
"diff_pair_gap": 0.25,
"diff_pair_via_gap": 0.25,
"diff_pair_width": 0.2,
"line_style": 0,
"microvia_diameter": 0.3,
"microvia_drill": 0.1,
"name": "Default",
"pcb_color": "rgba(0, 0, 0, 0.000)",
"priority": 2147483647,
"schematic_color": "rgba(0, 0, 0, 0.000)",
"track_width": 0.2,
"via_diameter": 0.6,
"via_drill": 0.3,
"wire_width": 6
}
],
"meta": {
"version": 4
},
"net_colors": null,
"netclass_assignments": null,
"netclass_patterns": []
},
"pcbnew": {
"last_paths": {
"gencad": "",
"idf": "",
"netlist": "",
"plot": "",
"pos_files": "",
"specctra_dsn": "",
"step": "",
"svg": "",
"vrml": ""
},
"page_layout_descr_file": ""
},
"schematic": {
"annotate_start_num": 0,
"bom_export_filename": "${PROJECTNAME}.csv",
"bom_fmt_presets": [],
"bom_fmt_settings": {
"field_delimiter": ",",
"keep_line_breaks": false,
"keep_tabs": false,
"name": "CSV",
"ref_delimiter": ",",
"ref_range_delimiter": "",
"string_delimiter": "\""
},
"bom_presets": [],
"bom_settings": {
"exclude_dnp": false,
"fields_ordered": [
{
"group_by": false,
"label": "Reference",
"name": "Reference",
"show": true
},
{
"group_by": true,
"label": "Value",
"name": "Value",
"show": true
},
{
"group_by": true,
"label": "Footprint",
"name": "Footprint",
"show": true
},
{
"group_by": false,
"label": "Datasheet",
"name": "Datasheet",
"show": true
},
{
"group_by": false,
"label": "Description",
"name": "Description",
"show": false
},
{
"group_by": false,
"label": "Qty",
"name": "${QUANTITY}",
"show": true
},
{
"group_by": false,
"label": "#",
"name": "${ITEM_NUMBER}",
"show": false
},
{
"group_by": true,
"label": "DNP",
"name": "${DNP}",
"show": true
},
{
"group_by": true,
"label": "Exclude from BOM",
"name": "${EXCLUDE_FROM_BOM}",
"show": true
},
{
"group_by": true,
"label": "Exclude from Board",
"name": "${EXCLUDE_FROM_BOARD}",
"show": true
}
],
"filter_string": "",
"group_symbols": true,
"include_excluded_from_bom": true,
"name": "",
"sort_asc": true,
"sort_field": "Reference"
},
"connection_grid_size": 50.0,
"drawing": {
"dashed_lines_dash_length_ratio": 12.0,
"dashed_lines_gap_length_ratio": 3.0,
"default_line_thickness": 6.0,
"default_text_size": 50.0,
"field_names": [],
"intersheets_ref_own_page": false,
"intersheets_ref_prefix": "",
"intersheets_ref_short": false,
"intersheets_ref_show": false,
"intersheets_ref_suffix": "",
"junction_size_choice": 3,
"label_size_ratio": 0.375,
"operating_point_overlay_i_precision": 3,
"operating_point_overlay_i_range": "~A",
"operating_point_overlay_v_precision": 3,
"operating_point_overlay_v_range": "~V",
"overbar_offset_ratio": 1.23,
"pin_symbol_size": 25.0,
"text_offset_ratio": 0.15
},
"legacy_lib_dir": "",
"legacy_lib_list": [],
"meta": {
"version": 1
},
"net_format_name": "",
"ngspice": {
"fix_include_paths": true,
"meta": {
"version": 0
},
"model_mode": 4,
"workbook_filename": ""
},
"page_layout_descr_file": "sensing",
"plot_directory": "",
"space_save_all_events": true,
"spice_current_sheet_as_root": false,
"spice_external_command": "spice \"%I\"",
"spice_model_current_sheet_as_root": true,
"spice_save_all_currents": false,
"spice_save_all_dissipations": false,
"spice_save_all_voltages": false,
"subpart_first_id": 65,
"subpart_id_separator": 0
},
"sheets": [
[
"90981571-11d1-4805-a2bb-89f0c5021ff9",
"Root"
]
],
"text_variables": {}
}
File diff suppressed because it is too large Load Diff
+18
View File
@@ -0,0 +1,18 @@
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends\
build-essential \
gcc-avr \
avrdude \
arduino-core-avr \
make \
&& apt-get clean
WORKDIR /usr/src/
COPY . .
RUN make all
+45
View File
@@ -0,0 +1,45 @@
PROJECT = plant-manager
MCU = atmega328p
F_CPU = 16000000UL
CC = avr-gcc
LD = $(CC)
OC = avr-objcopy
RM = rm -f
O_FLAG = -Os
BUILD_DIR = build
OBJ_DIR = $(BUILD_DIR)/obj
SRCS_C = source/adc.c source/moisture.c source/main.c source/pump.c source/eeprom.c source/twi.c
OBJS = $(addprefix $(OBJ_DIR)/, $(notdir $(SRCS_C:.c=.o)))
CFLAGS = -Wall $(O_FLAG) -DF_CPU=$(F_CPU) -mmcu=$(MCU) -Iinclude
LDFLAGS = -Wall $(O_FLAG) -mmcu=$(MCU)
LIBS = -lm
EXEC = atmega
ELF_TARGET = $(BUILD_DIR)/$(EXEC).elf
TARGET = $(BUILD_DIR)/$(EXEC).hex
all: $(TARGET)
$(shell mkdir -p $(OBJ_DIR))
$(shell mkdir -p $(BUILD_DIR))
$(ELF_TARGET): $(OBJS)
$(LD) $(LDFLAGS) $(OBJS) -o $@ $(LIBS)
$(OBJ_DIR)/%.o: source/%.c
$(CC) $(CFLAGS) -c $< -o $@
$(TARGET): $(ELF_TARGET)
$(OC) -O ihex -R .eeprom $< $@
clean:
$(RM) $(TARGET) $(ELF_TARGET) $(OBJS)
$(RM) -r $(BUILD_DIR)
.PHONY: all clean
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/env bash
set -e
IMAGE_NAME="vase-control-builder"
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
IMAGE_NAME="vase-control-builder"
DOCKERFILE="$SCRIPT_DIR/Dockerfile"
BUILD_CTX="$SCRIPT_DIR"
DEST_HEX="$SCRIPT_DIR/build/atmega.hex"
MCU="atmega328p"; PRG="usbasp"
docker build -t "$IMAGE_NAME" -f "$DOCKERFILE" "$BUILD_CTX"
mkdir -p "$(dirname "$DEST_HEX")"
docker run --rm "$IMAGE_NAME" \
cat /usr/src/build/atmega.hex > "$DEST_HEX"
command -v avrdude >/dev/null || { echo "Install avrdude"; exit 1; }
avrdude -v -p m328p -c usbasp -U flash:w:build/atmega.hex:i
+11
View File
@@ -0,0 +1,11 @@
#ifndef ADC_H
#define ADC_H
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
void adcInit(void);
uint16_t adcRead(uint8_t channel);
#endif
+58
View File
@@ -0,0 +1,58 @@
#ifndef CONFIG_H
#define CONFIG_H
#include <sys/types.h>
#include <stdint.h>
#include <avr/io.h>
#include "eeprom.h"
#define MOISTURE_SENSOR_A0 PC0
//#define MOISTURE_SENSOR_A1 PC1
//#define MOISTURE_SENSOR_A2 PC2
//#define MOISTURE_SENSOR_A3 PC3
//#define MOISTURE_SENSOR_A4 PC4
//#define MOISTURE_SENSOR_A5 PC5
//#define MOISTURE_SENSOR_A6 PC6
//#define MOISTURE_SENSOR_A7 PC7
//#define PUMP_D3 PD3
//#define PUMP_D4 PD4
//#define PUMP_D5 PD5
//#define PUMP_D6 PD6
#define PUMP_D7 PD7
#define TWI_SDA (1 << PD2)
#define TWI_SCL (1 << PD3)
inline void eeprom_init() {
#define DICT_SIZE 4
// EEPROM addresses
#define TWI_ADDR 0x22
#define SENSOR_READINGS 0x23
#define MOISTURE_MIN 0x24
#define MOISTURE_MAX 0x25
uint8_t keys[DICT_SIZE] = {
TWI_ADDR,
SENSOR_READINGS,
MOISTURE_MIN,
MOISTURE_MAX
};
// actual values
uint16_t values[DICT_SIZE] = {
0x30,
5,
400,
200
};
//NOTE: values are not re-initialized if != 0 because they may
// have been changed by the esp32 during previous runs
for (int i = 0; i < DICT_SIZE; i++) if (eepromRead(keys[i]) == 0) eepromWrite(keys[i], values[i]);
}
extern volatile uint16_t *pLastMoistureVal;
#endif
+11
View File
@@ -0,0 +1,11 @@
#ifndef EEPROM_H
#define EEPROM_H
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
uint8_t eepromRead(uint8_t address);
void eepromWrite(uint8_t address, uint8_t data);
#endif
+49
View File
@@ -0,0 +1,49 @@
#ifndef MOISTURE_H
#define MOISTURE_H
#include <stdint.h>
#include <stdbool.h>
#include "config.h"
static const int8_t sensorPins[] = {
#ifdef MOISTURE_SENSOR_A0
MOISTURE_SENSOR_A0,
#endif
#ifdef MOISTURE_SENSOR_A1
MOISTURE_SENSOR_A1,
#endif
#ifdef MOISTURE_SENSOR_A2
MOISTURE_SENSOR_A2,
#endif
#ifdef MOISTURE_SENSOR_A3
MOISTURE_SENSOR_A3,
#endif
#ifdef MOISTURE_SENSOR_A4
MOISTURE_SENSOR_A4,
#endif
#ifdef MOISTURE_SENSOR_A5
MOISTURE_SENSOR_A5,
#endif
#ifdef MOISTURE_SENSOR_A6
MOISTURE_SENSOR_A6,
#endif
#ifdef MOISTURE_SENSOR_A7
MOISTURE_SENSOR_A7,
#endif
};
#define SENSORS_NUM (sizeof(sensorPins) / sizeof(sensorPins[0]))
extern volatile bool readSensors;
void sensorsInit(void);
uint16_t moistureRead(void);
#endif
+38
View File
@@ -0,0 +1,38 @@
#ifndef PUMP_H
#define PUMP_H
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "config.h"
static const int8_t actuatorPins[] = {
#ifdef PUMP_D3
PUMP_D3,
#endif
#ifdef PUMP_D4
PUMP_D4,
#endif
#ifdef PUMP_D5
PUMP_D5,
#endif
#ifdef PUMP_D6
PUMP_D6,
#endif
#ifdef PUMP_D7
PUMP_D7,
#endif
};
#define ACTUATORS_NUM (sizeof(actuatorPins) / sizeof(actuatorPins[0]))
void pumpsInit(void);
void waterPlant(void);
#endif
+10
View File
@@ -0,0 +1,10 @@
#ifndef TWI_H
#define TWI_H
extern volatile uint16_t *pLastMoistureVal;
void twiInit(void);
void twiListen(void);
void twiRespond(void);
#endif
+27
View File
@@ -0,0 +1,27 @@
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
void adcInit(void) {
// Set reference voltage to AVcc (REFS0 = 1, REFS1 = 0)
ADMUX = (1 << REFS0);
// Enable ADC and set prescaler to 128 (for 16 MHz clock, gives 125 kHz ADC clock)
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}
uint16_t adcRead(uint8_t channel) {
// Select ADC pin (A0-A7) by setting MUX bits in ADMUX
// Pins A6 and A7 would make an 8 sensor array possible (for large vases).
// Achievable only when using the 328p as a DIP, through port C (PC6, PC7)
ADMUX = (ADMUX & 0xF8) | (channel & 0x07);
// Start conversion
ADCSRA |= (1 << ADSC);
// Wait for conversion to complete (ADSC becomes '0' when done)
while (ADCSRA & (1 << ADSC));
// Read ADC (reading order: ADCL --> ADCH)
return ADC;
}
+35
View File
@@ -0,0 +1,35 @@
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
uint8_t eepromRead(uint8_t address) {
// wait for previous write
while (EECR & (1 << EEPE));
//read from address
EEAR = address;
return EECR |= (1 << EERE);
}
void eepromWrite(uint8_t address, uint8_t data) {
// wait for previous write
while (EECR & (1 << EEPE));
if (eepromRead(address) != data) {
EEAR = address;
EEDR = data;
EECR |= (1 << EEMPE);
EECR |= (1 << EEPE);
}
}
void eepromFlush(uint8_t address) {
if (eepromRead(address) != 0) {
EEAR = address;
EEDR = 0;
EECR |= (1 << EEMPE);
EECR |= (1 << EEPE);
}
}
+54
View File
@@ -0,0 +1,54 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include <avr/interrupt.h>
#include "config.h"
#include "adc.h"
#include "moisture.h"
#include "pump.h"
#include "twi.h"
volatile uint16_t lastMoistureVal = 0;
volatile uint16_t *pLastMoistureVal = &lastMoistureVal;
ISR(TWI_vect) {
twiListen();
}
static void watchdogs(void) {
cli();
MCUSR &= ~(1 << WDRF);
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0);
sei();
}
static inline void enterSleep(void) {
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
sleep_enable();
sleep_cpu();
sleep_disable();
}
static void setup(void) {
adcInit();
twiInit();
sensorsInit();
pumpsInit();
watchdogs();
}
int main(void) {
setup();
pLastMoistureVal = &lastMoistureVal;
while(true) {
if ((*pLastMoistureVal = moistureRead()) < MOISTURE_MIN) waterPlant();
twiRespond();
enterSleep();
}
return -1;
}
+40
View File
@@ -0,0 +1,40 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include "moisture.h"
#include "config.h"
#include "adc.h"
volatile bool readSensors = false;
void sensorsInit(void) {
uint8_t sensorMask = 0;
for (uint8_t i = 0; i < SENSORS_NUM; i++) {
sensorMask |= (1 << sensorPins[i]);
}
DDRC &= ~sensorMask;
PORTC &= ~sensorMask;
}
static uint16_t moistureAverage(uint8_t sensorPin) {
uint16_t sum = 0;
for (uint8_t i = 0; i < SENSOR_READINGS; i++) {
sum += adcRead(sensorPin);
//TODO: implement variance check (if over a certain variance discard measurements for this cycle)
//TODO IMPORTANT: if value < 1 or > 1022, discard that measurement
}
return sum / SENSOR_READINGS;
}
uint16_t moistureRead(void) {
uint16_t overallSum = 0;
for (uint8_t i = 0; i < SENSORS_NUM; i++) {
uint16_t sensorAverage = moistureAverage(sensorPins[i]);
//TODO: if a sensor gives 1023, discard that sensor entirely (means it is disconnected or not working)
overallSum += sensorAverage;
}
return overallSum / SENSORS_NUM;
}
+32
View File
@@ -0,0 +1,32 @@
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "pump.h"
#include "config.h"
void pumpsInit(void) {
uint8_t actuatorMask = 0;
for (uint8_t i = 0; i < ACTUATORS_NUM; i++) {
actuatorMask |= (1 << actuatorPins[i]);
}
DDRD |= actuatorMask;
//PORTD &= ~(1 << actuatorMask);
}
static void triggerPump(uint8_t pump_pin) {
// Turn on pump
PORTD |= (1 << pump_pin);
_delay_ms(500);
// Here there could be the issue of the AVR hanging when pump is on
// Turn off pump
PORTD &= ~(1 << pump_pin);
}
void waterPlant(void) {
for (uint8_t i=0; i < ACTUATORS_NUM; i++) {
triggerPump(actuatorPins[i]);
}
}
+101
View File
@@ -0,0 +1,101 @@
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include "config.h"
#include "pump.h"
#include "twi.h"
#define BUFFER_SIZE 4
static uint8_t twiBuffer[BUFFER_SIZE] = {0};
static uint8_t bufferIndex = 0;
bool respondFlag = false;
static inline void twiReset(void) {
// Enable TWI; enable ACK; clear interrupt flag; enable twi external interrupt
TWCR = (1 << TWEN) | (1 << TWEA) | (1 << TWINT) | (1 << TWIE);
}
void twiInit(void) {
TWAR = ((eepromRead(TWI_ADDR)) << 1); //address definition found in config.h
twiReset();
}
static inline void twiSendAck(void) {
TWCR = (1 << TWEA) | (1 << TWINT);
}
static inline void twiSendNack(void) {
TWCR = (TWCR & ~(1 << TWEA)) | (1 << TWINT);
}
static void twiSendData(uint8_t data) {
TWDR = data;
twiSendAck();
}
void twiRespond(void) {
if (!respondFlag) return;
uint8_t cmd = twiBuffer[0];
uint8_t param = twiBuffer[1];
switch(cmd) {
// READ
case 0x01:
twiSendData(*pLastMoistureVal);
break;
case 0x02:
twiSendData(eepromRead(SENSOR_READINGS));
break;
case 0x03:
twiSendData(eepromRead(MOISTURE_MIN));
break;
case 0x04:
twiSendData(eepromRead(MOISTURE_MAX));
break;
// WRITE
case 0x05:
eepromWrite(SENSOR_READINGS, param);
twiSendAck();
break;
case 0x06:
eepromWrite(MOISTURE_MIN, param);
twiSendAck();
break;
case 0x07:
eepromWrite(MOISTURE_MAX, param);
twiSendAck();
break;
case 0x08:
waterPlant();
twiSendAck();
break;
default:
twiSendNack();
break;
}
}
void twiListen(void) {
switch (TWSR & 0xF8) {
case 0x60: // SLA+W received
bufferIndex = 0;
twiSendAck();
break;
case 0x80: // data received
if(bufferIndex < BUFFER_SIZE) {
twiBuffer[bufferIndex++] = TWDR;
twiSendAck();
} else twiSendNack();
break;
case 0xA0: // stop condition
respondFlag = true;
twiReset();
break;
default:
twiSendNack();
break;
}
}
+4
View File
@@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.16)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(plant-thing)
+48
View File
@@ -0,0 +1,48 @@
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \
apt-get install -y --no-install-recommends \
git \
wget \
flex \
bison \
gperf \
python3 \
python3-pip \
python3-venv \
cmake \
ninja-build \
ccache \
libffi-dev \
libssl-dev \
dfu-util \
libusb-1.0-0 \
&& apt-get autoremove
WORKDIR /usr/src/
ENV IDF_PATH=/usr/src/esp/esp-idf
ENV IDF_PATH_FORCE=1
RUN mkdir -p /usr/src/esp/firmware
RUN git clone --recursive https://github.com/espressif/esp-idf.git $IDF_PATH
RUN cd $IDF_PATH && ./install.sh esp32c3
COPY . /usr/src/esp/firmware/
WORKDIR /usr/src/esp/firmware/
# Create sdkconfig.defaults with correct flash settings
RUN echo "CONFIG_ESPTOOLPY_FLASHMODE=dio" > sdkconfig.defaults && \
echo "CONFIG_ESPTOOLPY_FLASHFREQ=40m" >> sdkconfig.defaults && \
echo "CONFIG_ESPTOOLPY_FLASHSIZE=4MB" >> sdkconfig.defaults
RUN rm -rf build && /bin/bash -c "source $IDF_PATH/export.sh && idf.py set-target esp32c3 && idf.py build"
RUN mkdir -p /usr/src/build && \
cp build/bootloader/bootloader.bin /usr/src/build/ && \
cp build/partition_table/partition-table.bin /usr/src/build/ && \
cp build/plant-thing.bin /usr/src/build/
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
set -e
IMAGE_NAME="esp32-builder"
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
DOCKERFILE="$SCRIPT_DIR/Dockerfile"
BUILD_CTX="$SCRIPT_DIR"
DEST_DIR="$SCRIPT_DIR/build"
docker build -t "$IMAGE_NAME" -f "$DOCKERFILE" "$BUILD_CTX"
mkdir -p "$DEST_DIR"
docker run --rm -v "$DEST_DIR":/output "$IMAGE_NAME" cp -r /usr/src/build/. /output/
#echo "Erasing flash..."
#esptool --chip esp32c3 --port /dev/tty.usbmodem101 erase-flash
esptool --chip esp32c3 --port /dev/tty.usbmodem101 --baud 115200 write-flash \
--flash-mode dio \
--flash-freq 40m \
--flash-size 4MB \
0x0000 "$DEST_DIR/bootloader.bin" \
0x8000 "$DEST_DIR/partition-table.bin" \
0x10000 "$DEST_DIR/plant-thing.bin"
screen -fn /dev/tty.usbmodem101 115200
+31
View File
@@ -0,0 +1,31 @@
#ifndef CONFIG_H
#define CONFIG_H
#pragma once
// WI-FI
#define SSID "your_wifi_ssid"
#define PASSWORD "your_wifi_password"
#define AUTH_MODE WIFI_AUTH_WPA2_PSK
// MQTT
#define MQTT_ADDR "mqtt://yourmqttserver"
#define MQTT_PORT 1883
#define MQTT_USER "your_username"
#define MQTT_PASS "your_password"
#define CMD_GET_MOISTURE 0x01
#define CMD_GET_SENSOR_READS 0x02
#define CMD_GET_MOISTURE_MIN 0x03
#define CMD_GET_MOISTURE_MAX 0x04
#define CMD_SET_SENSOR_READS 0x05 // [cmd, value]
#define CMD_SET_PARAMS 0x06 // [cmd, min, max, reads]
#define CMD_FORCE_PUMP 0x07 // [cmd]
// Change based on how many vases max to manage [1 to ~100]
// larger numberss will require larger arrays stored in memory
// see AVR limitation on TWI addresses
#define SLAVES_NUMBER 8
#endif
+12
View File
@@ -0,0 +1,12 @@
#ifndef I2C_HPP
#define I2C_HPP
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
extern TaskHandle_t i2c_task;
void i2cTask(void *pvParameters);
#endif
+15
View File
@@ -0,0 +1,15 @@
#ifndef MAIN_HPP
#define MAIN_HPP
#pragma once
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
extern volatile bool criticalErrorFlag;
extern EventGroupHandle_t connectivity_event_group;
#define WIFI_CONNECTED_BIT BIT0
#define MQTT_CONNECTED_BIT BIT1
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef MQTT_HPP
#define MQTT_HPP
#pragma once
void mqttTask(void *pvParameters);
#endif
+8
View File
@@ -0,0 +1,8 @@
#ifndef WIFI_HPP
#define WIFI_HPP
#pragma once
void wifiTask(void *pvParameters);
#endif
+16
View File
@@ -0,0 +1,16 @@
idf_component_register(
SRCS "./main.cpp"
"./wifi.cpp"
"./i2c.cpp"
"./mqtt.cpp"
INCLUDE_DIRS "../include"
REQUIRES esp_wifi
nvs_flash
esp_pm
esp_hw_support
esp_system
freertos
log
mqtt
esp_driver_i2c
)
+100
View File
@@ -0,0 +1,100 @@
#include <cstdint>
#include <stdint.h>
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_task_wdt.h"
#include "driver/i2c_master.h"
#include "esp_log.h"
#include "config-erick.h"
#define I2C_TASK_TIMEOUT_MS 4500
// for ESP32-C3
#define I2C_MASTER_SCL_IO ((gpio_num_t)9)
#define I2C_MASTER_SDA_IO ((gpio_num_t)8)
#define DATA_LENGTH 100
static const char* TAG = "I2C";
TaskHandle_t i2c_task = NULL;
i2c_master_bus_handle_t bus_handle;
static i2c_master_dev_handle_t slave_handles[SLAVES_NUMBER];
uint8_t slave_count = 0;
uint8_t slave_addrs[SLAVES_NUMBER];
uint8_t data_rd[DATA_LENGTH];
static void register_slave(uint8_t addr) {
i2c_device_config_t slave_dev_cfg = {};
slave_dev_cfg.dev_addr_length = I2C_ADDR_BIT_LEN_7;
slave_dev_cfg.device_address = addr;
slave_dev_cfg.scl_speed_hz = 100000;
ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &slave_dev_cfg, &slave_handles[slave_count]));
slave_addrs[slave_count++] = addr;
}
static void i2c_init(void) {
i2c_master_bus_config_t i2c_mst_config = {};
i2c_mst_config.i2c_port = I2C_NUM_0;
i2c_mst_config.scl_io_num = I2C_MASTER_SCL_IO;
i2c_mst_config.sda_io_num = I2C_MASTER_SDA_IO;
i2c_mst_config.clk_source = I2C_CLK_SRC_DEFAULT;
i2c_mst_config.glitch_ignore_cnt = 7;
i2c_mst_config.intr_priority = 1;
i2c_mst_config.trans_queue_depth = 4;
ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
register_slave(0x30);
register_slave(0x31);
}
static void i2c_send(uint32_t packet) {
uint8_t cmd = (packet >> 24) & 0xFF;
uint8_t slave_addr = (packet >> 16) & 0xFF;
uint8_t param = packet & 0xFF;
i2c_master_dev_handle_t dev = NULL;
for(uint8_t i = 0; i < slave_count; i++) {
if(slave_addrs[i] == slave_addr) {
dev = slave_handles[i];
break;
}
}
if(!dev) { ESP_LOGE(TAG,"Slave 0x%02X not found", slave_addr); return; }
uint8_t tx[2] = {cmd, param};
esp_err_t err;
switch(cmd) {
case CMD_GET_MOISTURE:
case CMD_GET_SENSOR_READS:
case CMD_GET_MOISTURE_MIN:
case CMD_GET_MOISTURE_MAX: {
uint8_t rx;
err = i2c_master_transmit_receive(dev, tx, 2, &rx, 1, 250);
if(err == ESP_OK) ESP_LOGI(TAG,"I2C READ cmd=0x%02X val=%u", cmd, rx);
break;
}
default:
err = i2c_master_transmit(dev, tx, 2, 250);
break;
}
if(err != ESP_OK) ESP_LOGE(TAG,"I2C transaction failed: %s", esp_err_to_name(err));
}
void i2cTask(void *pvParameters) {
i2c_init();
ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
uint32_t packet;
for(;;) {
if(xTaskNotifyWait(0, 0, &packet, pdMS_TO_TICKS(I2C_TASK_TIMEOUT_MS)) == pdPASS) {
i2c_send(packet);
}
ESP_ERROR_CHECK(esp_task_wdt_reset());
vTaskDelay(pdMS_TO_TICKS(150));
}
}
+2
View File
@@ -0,0 +1,2 @@
dependencies:
espressif/mqtt: "*"
+59
View File
@@ -0,0 +1,59 @@
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/semphr.h"
#include "esp_system.h"
#include "esp_log.h"
#include "esp_pm.h"
#include "esp_task_wdt.h"
#include "wifi.hpp"
#include "i2c.hpp"
#include "mqtt.hpp"
#define WATCHDOG_KEEPALIVE_MS 8000
EventGroupHandle_t connectivity_event_group;
static const char* TAG = "MAIN";
volatile bool criticalErrorFlag = false;
static void watchdogTask(void *pvParameters) {
esp_task_wdt_config_t twdt_config = {
.timeout_ms = 12000,
.idle_core_mask = 0,
.trigger_panic = true,
};
ESP_ERROR_CHECK(esp_task_wdt_deinit());
ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
for(;;) {
if(criticalErrorFlag) {
ESP_LOGE(TAG, "Critical error flag raised. Rebooting.");
esp_restart();
}
ESP_ERROR_CHECK(esp_task_wdt_reset());
ESP_LOGV(TAG, "WDT reset");
vTaskDelay(pdMS_TO_TICKS(WATCHDOG_KEEPALIVE_MS));
}
}
extern "C" void app_main(void)
{
static const esp_pm_config_t pm_cfg = {
.max_freq_mhz = 160,
.min_freq_mhz = 10,
.light_sleep_enable = true
};
esp_pm_configure(&pm_cfg);
connectivity_event_group = xEventGroupCreate();
xTaskCreate(watchdogTask, "watchdogs", 2048, NULL, configMAX_PRIORITIES-1, NULL);
xTaskCreate(wifiTask, "wifi", 4096, NULL, configMAX_PRIORITIES-4, NULL);
xTaskCreate(i2cTask, "i2c", 4096, NULL, configMAX_PRIORITIES-6, &i2c_task);
xTaskCreate(mqttTask, "mqtt", 2048, NULL, configMAX_PRIORITIES-8, NULL);
}
+156
View File
@@ -0,0 +1,156 @@
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_task_wdt.h"
#include "esp_event.h"
#include "esp_log.h"
#include "stdlib.h"
#include "string.h"
#include "mqtt_client.h"
#include "main.hpp"
#include "i2c.hpp"
#include "config.h"
#include <cstdint>
#define MQTT_TASK_TIMEOUT_MS 3000
#define DEFAULT_SLAVE_ADDR 0x30
static const char* TAG = "MQTT";
static esp_mqtt_client_handle_t mqtt_client = NULL;
static char rx_buffer[50];
static void mqtt_subscribe(void) {
esp_mqtt_client_subscribe(mqtt_client, "/plant/moisture/qos0", 0);
esp_mqtt_client_subscribe(mqtt_client, "/plant/humidity/qos0", 0);
}
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
esp_mqtt_event_handle_t event =(esp_mqtt_event_handle_t)event_data;
switch(event->event_id) {
case MQTT_EVENT_CONNECTED:
xEventGroupSetBits(connectivity_event_group, MQTT_CONNECTED_BIT);
ESP_LOGV(TAG, "Connected to broker");
mqtt_subscribe();
ESP_LOGV(TAG, "Subscribed to topic");
break;
case MQTT_EVENT_DISCONNECTED:
xEventGroupClearBits(connectivity_event_group, MQTT_CONNECTED_BIT);
ESP_LOGW(TAG, "Disconnected from broker");
break;
case MQTT_EVENT_DATA:
{
ESP_LOGD(TAG, "Data received");
int len = event->data_len;
if(len > sizeof(rx_buffer) - 1) len = sizeof(rx_buffer) - 1;
memcpy(rx_buffer, event->data, len);
rx_buffer[len] = '\0';
break;
}
case MQTT_EVENT_ERROR:
ESP_LOGE(TAG, "Error event");
if(event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) ESP_LOGE(TAG, "Network Error: %s", strerror(event->error_handle->esp_transport_sock_errno));
else if(event->error_handle->error_type == MQTT_ERROR_TYPE_CONNECTION_REFUSED) ESP_LOGE(TAG, "Connection Refused! Reason code: 0x%x", event->error_handle->connect_return_code);
break;
default:
break;
}
}
static void mqtt_init(void) {
esp_mqtt_client_config_t mqtt_cfg = {};
mqtt_cfg.broker.address.uri = MQTT_ADDR;
mqtt_cfg.credentials.username = MQTT_USER;
mqtt_cfg.credentials.authentication.password = MQTT_PASS;
mqtt_client = esp_mqtt_client_init(&mqtt_cfg);
if(mqtt_client == NULL) {
ESP_LOGE(TAG, "esp_mqtt_client_init returned NULL");
criticalErrorFlag = true;
}
esp_mqtt_client_register_event(mqtt_client, (esp_mqtt_event_id_t)ESP_EVENT_ANY_ID, mqtt_event_handler, NULL);
esp_mqtt_client_start(mqtt_client);
}
void mqtt_publish(void) {}
void mqttTask(void *pvParameters) {
ESP_LOGV(TAG, "Task started");
ESP_LOGV(TAG, "Waiting for Wi-Fi before initializing server");
xEventGroupWaitBits(connectivity_event_group, WIFI_CONNECTED_BIT, pdFALSE, pdTRUE, portMAX_DELAY);
ESP_LOGV(TAG, "Server initialized");
mqtt_init();
ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
for(;;) {
ESP_LOGV(TAG, "Checking Wi-Fi connection...");
EventBits_t bits = xEventGroupWaitBits(connectivity_event_group, WIFI_CONNECTED_BIT | MQTT_CONNECTED_BIT, pdFALSE, pdTRUE, pdMS_TO_TICKS(MQTT_TASK_TIMEOUT_MS));
if ((bits & (WIFI_CONNECTED_BIT | MQTT_CONNECTED_BIT)) == (WIFI_CONNECTED_BIT | MQTT_CONNECTED_BIT)) {
ESP_LOGV(TAG, "Wi-Fi and MQTT up");
uint8_t params[3] = {0};
uint8_t param_len = 0;
uint8_t i2c_cmd = 0;
uint8_t slave_addr = DEFAULT_SLAVE_ADDR;
char *action = strtok(rx_buffer, ":");
char *target = strtok(NULL, ":");
char *value = strtok(NULL, ":");
char *slave = strtok(NULL, ":");
if(slave) slave_addr = (uint8_t)strtol(slave, NULL, 0);
if(action && target) {
if (strcmp(action, "READ") == 0) {
if (strcmp(target, "moisture") == 0) i2c_cmd = CMD_GET_MOISTURE;
else if (strcmp(target, "eeprom") == 0 && value) {
if (strcmp(value, "sensor_reads") == 0) i2c_cmd = CMD_GET_SENSOR_READS;
else if (strcmp(value, "moisture_min") == 0) i2c_cmd = CMD_GET_MOISTURE_MIN;
else if (strcmp(value, "moisture_max") == 0) i2c_cmd = CMD_GET_MOISTURE_MAX;
}
} else if (strcmp(action, "WRITE") == 0) {
if (strcmp(target, "force") == 0) i2c_cmd = CMD_FORCE_PUMP;
else if (strcmp(target, "eeprom") == 0 && value) {
if (strncmp(value, "params:", 7) == 0) {
sscanf(value + 7, "%hhu,%hhu,%hhu", &params[0], &params[1], &params[2]);
i2c_cmd = CMD_SET_PARAMS;
param_len = 3;
}
else {
uint8_t v = (uint8_t)atoi(value);
if (strcmp(value, "sensor_reads") == 0) {
i2c_cmd = CMD_SET_SENSOR_READS;
params[0] = v;
param_len = 1;
}
}
}
}
}
uint32_t packet = (i2c_cmd<<24) | (slave_addr<<16) | params[0];
xTaskNotify(i2c_task, packet, eSetValueWithOverwrite);
} else ESP_LOGW(TAG, "Wi-Fi or MQTT down");
ESP_ERROR_CHECK(esp_task_wdt_reset());
ESP_LOGV(TAG, "Task reset");
vTaskDelay(pdMS_TO_TICKS(3000));
}
ESP_LOGW(TAG, "Task exited");
}
+87
View File
@@ -0,0 +1,87 @@
#include "freertos/FreeRTOS.h"
#include "freertos/event_groups.h"
#include "esp_task_wdt.h"
#include "esp_wifi.h"
#include "esp_event.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "main.hpp"
#include "config.h"
#define WIFI_TIMEOUT_MS 4500
static const char* TAG = "WIFI";
static void wifi_event_handler(void* arg, esp_event_base_t event_base, int32_t event_id, void* event_data) {
if(event_base == WIFI_EVENT) {
switch(event_id) {
case WIFI_EVENT_STA_START:
ESP_LOGV(TAG, "Process started, connecting...");
esp_wifi_connect();
break;
case WIFI_EVENT_STA_DISCONNECTED: {
wifi_event_sta_disconnected_t* disconn =(wifi_event_sta_disconnected_t*) event_data;
ESP_LOGW(TAG, "Disconnected, reason: %d", disconn->reason);
xEventGroupClearBits(connectivity_event_group, WIFI_CONNECTED_BIT);
esp_wifi_connect();
vTaskDelay(pdMS_TO_TICKS(2000));
break;
}
default:
break;
}
}
else if(event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) {
ip_event_got_ip_t* event =(ip_event_got_ip_t*) event_data;
ESP_LOGD(TAG, "Got IP: " IPSTR, IP2STR(&event->ip_info.ip));
xEventGroupSetBits(connectivity_event_group, WIFI_CONNECTED_BIT);
}
}
static void wifi_init_sta(void) {
esp_err_t nvs_err = nvs_flash_init();
if(nvs_err == ESP_ERR_NVS_NO_FREE_PAGES || nvs_err == ESP_ERR_NVS_NEW_VERSION_FOUND) {
ESP_ERROR_CHECK(nvs_flash_erase());
ESP_ERROR_CHECK(nvs_flash_init());
}
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());
esp_netif_create_default_wifi_sta();
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
ESP_ERROR_CHECK(esp_wifi_init(&cfg));
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL));
ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, IP_EVENT_STA_GOT_IP, &wifi_event_handler, NULL, NULL));
wifi_config_t wifi_config{};
strncpy((char*)wifi_config.sta.ssid, SSID, sizeof(wifi_config.sta.ssid));
strncpy((char*)wifi_config.sta.password, PASSWORD, sizeof(wifi_config.sta.password));
wifi_config.sta.threshold.authmode = AUTH_MODE;
wifi_config.sta.pmf_cfg.capable = true;
wifi_config.sta.pmf_cfg.required = false;
ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA));
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
}
void wifiTask(void *pvParameters) {
ESP_LOGV(TAG, "Task started");
wifi_init_sta();
ESP_ERROR_CHECK(esp_task_wdt_add(NULL));
for(;;) {
ESP_ERROR_CHECK(esp_task_wdt_reset());
ESP_LOGV(TAG, "Task reset");
vTaskDelay(pdMS_TO_TICKS(WIFI_TIMEOUT_MS));
}
ESP_LOGW(TAG, "Task exited");
}
-41
View File
@@ -1,41 +0,0 @@
PROJECT = plant-manager
# Flags
MCU = atmega328p
F_CPU = 16000000UL
CC = avr-gcc
OBJCOPY = avr-objcopy
AVRDUDE = avrdude
CFLAGS = -Wall -Os -DF_CPU=$(F_CPU) -mmcu=$(MCU)
PROGRAMMER = arduino
PORT = /dev/ttyACM0
SRC = main.c
OBJ = $(SRC:.c=.o)
# Default target
all: $(PROJECT).hex
# Compiler
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $@
# Linker
$(PROJECT).elf: $(OBJ)
$(CC) $(CFLAGS) -o $@ $^
# Create hex file
$(PROJECT).hex: $(PROJECT).elf
$(OBJCOPY) -O ihex -R .eeprom $< $@
# Uploader
upload: $(PROJECT).hex
$(AVRDUDE) -p $(MCU) -c $(PROGRAMMER) -P $(PORT) -U flash:w:$<:i
# Cleaner
clean:
rm -f *.o *.elf *.hex
.PHONY: all upload clean
-7
View File
@@ -1,7 +0,0 @@
#ifndef CONFIG_H
#define CONFIG_H
#define MOISTURE_SENSOR_A0 A0
#define SENSOR_READINGS 3
#endif
-42
View File
@@ -1,42 +0,0 @@
#include <stdint.h>
#include <avr/sleep.h>
#include <avr/wdt.h>
#include "config.h"
#include "moisture.h"
ISR(WDT_vect) {
readSensors = true;
}
void watchdogs(void) {
cli();
MCUSR &= ~(1 << WDRF);
WDTCSR |= (1 << WDCE) | (1 << WDE);
WDTCSR = (1 << WDIE) | (1 << WDP3) | (1 << WDP0);
sei();
}
void enterSleep(void) {
set_sleep_mode(SLEEP_MODE_IDLE);
sleep_enable();
sleep_cpu();
sleep_disable();
}
void setup(void) {
Serial.begin(9600);
initMoistureSensor();
watchdogs();
}
void loop(void) {
if (readSensors) {
int16_t result = readMoisture();
if (result != -1) {
Serial.println(result);
readSensors = false;
}
}
enterSleep();
}
-36
View File
@@ -1,36 +0,0 @@
#include <Arduino.h>
#include <stdint.h>
#include "moisture.h"
#include "config.h"
static int16_t moistureReadingSum = 0;
static int8_t moistureReadingCount = 0;
volatile bool readSensors = false;
void initMoistureSensor(void) {
pinMode(MOISTURE_SENSOR_A0, INPUT);
}
void triggerSensorRead(void) {
readSensors = true;
}
int16_t readMoisture(void) {
if (!readSensors)
return -1;
moistureReadingSum += analogRead(MOISTURE_SENSOR_A0);
moistureReadingCount++;
if (moistureReadingCount >= SENSOR_READINGS) {
int16_t avg = moistureReadingSum / SENSOR_READINGS;
//Serial.println(avg);
moistureReadingSum = 0;
moistureReadingCount = 0;
readSensors = false;
return avg;
} else readSensors = true;
return -1;
}
-13
View File
@@ -1,13 +0,0 @@
#ifndef MOISTURE_H
#define MOISTURE_H
#include <stdint.h>
#include <stdbool.h>
void initMoistureSensor(void);
int16_t readMoisture(void);
void triggerSensorRead(void);
extern volatile bool readSensors;
#endif