commit 73cdedb9393ea7427aa22eae1f7b381e5f7937b5 Author: sam rolfe Date: Fri Dec 5 16:07:03 2025 +1100 Initial committ: Fish feeder and temp monitor diff --git a/.vscode/arduino.json b/.vscode/arduino.json new file mode 100644 index 0000000..567d5aa --- /dev/null +++ b/.vscode/arduino.json @@ -0,0 +1,6 @@ +{ + "configuration": "JTAGAdapter=default,PSRAM=disabled,PartitionScheme=default,CPUFreq=240,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,LoopCore=1,EventsCore=1,DebugLevel=none,EraseFlash=none,ZigbeeMode=default", + "board": "esp32:esp32:esp32", + "port": "/dev/ttyUSB0", + "sketch": "fish_feeder.ino" +} \ No newline at end of file diff --git a/.vscode/c_cpp_properties.json b/.vscode/c_cpp_properties.json new file mode 100644 index 0000000..9f89c45 --- /dev/null +++ b/.vscode/c_cpp_properties.json @@ -0,0 +1,453 @@ +{ + "version": 4, + "configurations": [ + { + "name": "Arduino", + "compilerPath": "/home/sam/.arduino15/packages/esp32/tools/esp-x32/2411/bin/xtensa-esp32-elf-g++", + "compilerArgs": [ + "-MMD", + "-w", + "-Werror=return-type", + "-iprefix" + ], + "intelliSenseMode": "gcc-x64", + "includePath": [ + "/media/sam/8294CD2994CD2111/Users/Dell/Documents/Arduino/fish_feeder", + "/home/sam/.arduino15/packages/esp32/tools/esp32-arduino-libs/idf-release_v5.5-129cd0d2-v4/esp32/qio_qspi/include", + "/home/sam/.arduino15/packages/esp32/hardware/esp32/3.3.1/cores/esp32", + "/home/sam/.arduino15/packages/esp32/hardware/esp32/3.3.1/variants/esp32", + "/home/sam/.arduino15/packages/esp32/hardware/esp32/3.3.1/libraries/WiFi/src", + "/home/sam/.arduino15/packages/esp32/hardware/esp32/3.3.1/libraries/Network/src", + "/home/sam/Arduino/libraries/PubSubClient/src", + "/home/sam/Arduino/libraries/OneWire", + "/home/sam/Arduino/libraries/DallasTemperature", + "/home/sam/.arduino15/packages/esp32/tools/esp-x32/2411/xtensa-esp-elf/include/c++/14.2.0", + "/home/sam/.arduino15/packages/esp32/tools/esp-x32/2411/xtensa-esp-elf/include/c++/14.2.0/xtensa-esp-elf/esp32", + "/home/sam/.arduino15/packages/esp32/tools/esp-x32/2411/xtensa-esp-elf/include/c++/14.2.0/backward", + "/home/sam/.arduino15/packages/esp32/tools/esp-x32/2411/lib/gcc/xtensa-esp-elf/14.2.0/include", + "/home/sam/.arduino15/packages/esp32/tools/esp-x32/2411/lib/gcc/xtensa-esp-elf/14.2.0/include-fixed", + "/home/sam/.arduino15/packages/esp32/tools/esp-x32/2411/xtensa-esp-elf/include" + ], + "forcedInclude": [ + "/home/sam/.arduino15/packages/esp32/hardware/esp32/3.3.1/cores/esp32/Arduino.h" + ], + "cStandard": "c11", + "cppStandard": "c++11", + "defines": [ + "F_CPU=240000000L", + "ARDUINO=10607", + "ARDUINO_ESP32_DEV", + "ARDUINO_ARCH_ESP32", + "ARDUINO_BOARD=\"ESP32_DEV\"", + "ARDUINO_VARIANT=\"esp32\"", + "ARDUINO_PARTITION_default", + "ARDUINO_HOST_OS=\"linux\"", + "ARDUINO_FQBN=\"esp32:esp32:esp32:JTAGAdapter=default,PSRAM=disabled,PartitionScheme=default,CPUFreq=240,FlashMode=qio,FlashFreq=80,FlashSize=4M,UploadSpeed=921600,LoopCore=1,EventsCore=1,DebugLevel=none,EraseFlash=none,ZigbeeMode=default\"", + "ESP32=ESP32", + "CORE_DEBUG_LEVEL=0", + "ARDUINO_RUNNING_CORE=1", + "ARDUINO_EVENT_RUNNING_CORE=1", + "ARDUINO_USB_CDC_ON_BOOT=0", + "__DBL_MIN_EXP__=(-1021)", + "__XCHAL_HAVE_FP=1", + "__cpp_nontype_template_parameter_auto=201606L", + "__UINT_LEAST16_MAX__=0xffff", + "__ATOMIC_ACQUIRE=2", + "__FLT_MIN__=1.1754943508222875e-38F", + "__GCC_IEC_559_COMPLEX=0", + "__XCHAL_HAVE_PREDICTED_BRANCHES=0", + "__cpp_aggregate_nsdmi=201304L", + "__UINT_LEAST8_TYPE__=unsigned char", + "__INTMAX_C(c)=c ## LL", + "__XCHAL_HAVE_ADDX=1", + "__CHAR_BIT__=8", + "__XCHAL_DCACHE_LINESIZE=16", + "__XTENSA_MARCH_EARLIEST=260003", + "__XCHAL_DCACHE_LINEWIDTH=4", + "__UINT8_MAX__=0xff", + "__WINT_MAX__=0xffffffffU", + "__FLT32_MIN_EXP__=(-125)", + "__cpp_static_assert=201411L", + "__ORDER_LITTLE_ENDIAN__=1234", + "__SIZE_MAX__=0xffffffffU", + "__WCHAR_MAX__=0xffff", + "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1=1", + "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2=1", + "__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4=1", + "__DBL_DENORM_MIN__=double(4.9406564584124654e-324L)", + "__GCC_ATOMIC_CHAR_LOCK_FREE=2", + "__GCC_IEC_559=0", + "__FLT32X_DECIMAL_DIG__=17", + "__FLT_EVAL_METHOD__=0", + "__cpp_binary_literals=201304L", + "__FLT64_DECIMAL_DIG__=17", + "__cpp_noexcept_function_type=201510L", + "__GCC_ATOMIC_CHAR32_T_LOCK_FREE=2", + "__cpp_variadic_templates=200704L", + "__UINT_FAST64_MAX__=0xffffffffffffffffULL", + "__SIG_ATOMIC_TYPE__=int", + "__DBL_MIN_10_EXP__=(-307)", + "__FINITE_MATH_ONLY__=0", + "__cpp_variable_templates=201304L", + "__XCHAL_HAVE_L32R=1", + "__FLT32X_MAX_EXP__=1024", + "__GNUC_PATCHLEVEL__=0", + "__FLT32_HAS_DENORM__=1", + "__UINT_FAST8_MAX__=0xffffffffU", + "__cpp_rvalue_reference=200610L", + "__XCHAL_HAVE_LOOPS=1", + "__cpp_nested_namespace_definitions=201411L", + "__XCHAL_DEBUGLEVEL=6", + "__INT8_C(c)=c", + "__XCHAL_HAVE_DFP_RECIP=0", + "__INT_LEAST8_WIDTH__=8", + "__cpp_variadic_using=201611L", + "__UINT_LEAST64_MAX__=0xffffffffffffffffULL", + "__INT_LEAST8_MAX__=0x7f", + "__cpp_attributes=200809L", + "__cpp_capture_star_this=201603L", + "__SHRT_MAX__=0x7fff", + "__LDBL_MAX__=1.7976931348623157e+308L", + "__cpp_if_constexpr=201606L", + "__XCHAL_ICACHE_LINESIZE=16", + "__LDBL_IS_IEC_60559__=1", + "__UINT_LEAST8_MAX__=0xff", + "__GCC_ATOMIC_BOOL_LOCK_FREE=2", + "__UINTMAX_TYPE__=long long unsigned int", + "__cpp_nsdmi=200809L", + "__FLT_EVAL_METHOD_TS_18661_3__=0", + "__UINT32_MAX__=0xffffffffUL", + "__GXX_EXPERIMENTAL_CXX0X__=1", + "__LDBL_MAX_EXP__=1024", + "__WINT_MIN__=0U", + "__FLT32X_IS_IEC_60559__=1", + "__XCHAL_HAVE_THREADPTR=1", + "__INT_LEAST16_WIDTH__=16", + "__SCHAR_MAX__=0x7f", + "__WCHAR_MIN__=0", + "__XCHAL_ICACHE_LINEWIDTH=4", + "__INT64_C(c)=c ## LL", + "__GCC_ATOMIC_POINTER_LOCK_FREE=2", + "__ATOMIC_SEQ_CST=5", + "__SIZEOF_INT__=4", + "__FLT32X_MANT_DIG__=53", + "__GCC_ATOMIC_CHAR16_T_LOCK_FREE=2", + "__cpp_aligned_new=201606L", + "__XCHAL_HAVE_FP_RECIP=1", + "__FLT32_MAX_10_EXP__=38", + "__STDC_HOSTED__=1", + "__XCHAL_HAVE_MUL32=1", + "__XTENSA_EL__=1", + "__cpp_decltype_auto=201304L", + "__DBL_DIG__=15", + "__XCHAL_HAVE_MUL16=1", + "__FLT_EPSILON__=1.1920928955078125e-7F", + "__GXX_WEAK__=1", + "__SHRT_WIDTH__=16", + "__FLT32_IS_IEC_60559__=1", + "__LDBL_MIN__=2.2250738585072014e-308L", + "__DBL_IS_IEC_60559__=1", + "__cpp_threadsafe_static_init=200806L", + "__cpp_enumerator_attributes=201411L", + "__XCHAL_HAVE_MMU=0", + "__FLT32X_HAS_INFINITY__=1", + "__INT32_MAX__=0x7fffffffL", + "__XCHAL_HAVE_DIV32=1", + "__INT_WIDTH__=32", + "__XTENSA_MARCH_LATEST=260003", + "__DECIMAL_DIG__=17", + "__FLT64_EPSILON__=2.2204460492503131e-16F64", + "__INT16_MAX__=0x7fff", + "__FLT64_MIN_EXP__=(-1021)", + "__XCHAL_DCACHE_SIZE=0", + "__LDBL_HAS_QUIET_NAN__=1", + "__cpp_return_type_deduction=201304L", + "__XCHAL_HAVE_BOOLEANS=1", + "__FLT64_MANT_DIG__=53", + "__XTHAL_ABI_WINDOWED=0", + "__GNUC__=14", + "__GXX_RTTI=1", + "__FLT_HAS_DENORM__=1", + "__SIZEOF_LONG_DOUBLE__=8", + "__XCHAL_HAVE_CONST16=0", + "__BIGGEST_ALIGNMENT__=16", + "__STDC_UTF_16__=1", + "__FLT64_MAX_10_EXP__=308", + "__cpp_delegating_constructors=200604L", + "__DBL_MAX__=double(1.7976931348623157e+308L)", + "__cpp_raw_strings=200710L", + "__INT_FAST32_MAX__=0x7fffffff", + "__DBL_HAS_INFINITY__=1", + "__cpp_deduction_guides=201703L", + "__HAVE_SPECULATION_SAFE_VALUE=1", + "__cpp_fold_expressions=201603L", + "__INTPTR_WIDTH__=32", + "__UINT_LEAST32_MAX__=0xffffffffUL", + "__FLT32X_HAS_DENORM__=1", + "__INT_FAST16_TYPE__=int", + "__XCHAL_HAVE_RELEASE_SYNC=1", + "__LDBL_HAS_DENORM__=1", + "__cplusplus=201703L", + "__cpp_ref_qualifiers=200710L", + "__INT_LEAST32_MAX__=0x7fffffffL", + "__DEPRECATED=1", + "__cpp_rvalue_references=200610L", + "__DBL_MAX_EXP__=1024", + "__WCHAR_WIDTH__=16", + "__FLT32_MAX__=3.4028234663852886e+38F32", + "__GCC_ATOMIC_LONG_LOCK_FREE=2", + "__PTRDIFF_MAX__=0x7fffffff", + "__FLT32_HAS_QUIET_NAN__=1", + "__GNUG__=14", + "__LONG_LONG_MAX__=0x7fffffffffffffffLL", + "__SIZEOF_SIZE_T__=4", + "__SIZEOF_WINT_T__=4", + "__FLT32X_DIG__=15", + "__LONG_LONG_WIDTH__=64", + "__cpp_initializer_lists=200806L", + "__FLT32_MAX_EXP__=128", + "__XCHAL_HAVE_MINMAX=1", + "__cpp_hex_float=201603L", + "__XCHAL_NUM_IBREAK=2", + "__GXX_ABI_VERSION=1019", + "__FLT_MIN_EXP__=(-125)", + "__cpp_lambdas=200907L", + "__INT_FAST64_TYPE__=long long int", + "__FP_FAST_FMAF=1", + "__FLT64_DENORM_MIN__=4.9406564584124654e-324F64", + "__DBL_MIN__=double(2.2250738585072014e-308L)", + "__SIZEOF_POINTER__=4", + "__DBL_HAS_QUIET_NAN__=1", + "__FLT32X_EPSILON__=2.2204460492503131e-16F32x", + "__XSHAL_HAVE_TEXT_SECTION_LITERALS=1", + "__FLT64_MIN_10_EXP__=(-307)", + "__REGISTER_PREFIX__", + "__UINT16_MAX__=0xffff", + "__XSHAL_USE_ABSOLUTE_LITERALS=0", + "__LDBL_HAS_INFINITY__=1", + "__FLT32_MIN__=1.1754943508222875e-38F32", + "__UINT8_TYPE__=unsigned char", + "__FLT_DIG__=6", + "__NO_INLINE__=1", + "__DEC_EVAL_METHOD__=2", + "__FLT_MANT_DIG__=24", + "__LDBL_DECIMAL_DIG__=17", + "__VERSION__=\"14.2.0\"", + "__UINT64_C(c)=c ## ULL", + "__XCHAL_NUM_AREGS=64", + "__cpp_unicode_characters=201411L", + "__XCHAL_HAVE_XEA3=0", + "__GCC_ATOMIC_INT_LOCK_FREE=2", + "__XCHAL_HAVE_DENSITY=1", + "__FLT32_MANT_DIG__=24", + "__FLOAT_WORD_ORDER__=__ORDER_LITTLE_ENDIAN__", + "__XCHAL_HAVE_CLAMPS=0", + "__XCHAL_HAVE_DFP_RSQRT=0", + "__cpp_aggregate_bases=201603L", + "__XCHAL_HAVE_NSA=1", + "__XCHAL_HAVE_WINDOWED=1", + "__SCHAR_WIDTH__=8", + "__INT32_C(c)=c ## L", + "__ORDER_PDP_ENDIAN__=3412", + "__INT_FAST32_TYPE__=int", + "__UINT_LEAST16_TYPE__=short unsigned int", + "__DBL_HAS_DENORM__=1", + "__XCHAL_HAVE_DEBUG=1", + "__cpp_rtti=199711L", + "__SIZE_TYPE__=unsigned int", + "__UINT64_MAX__=0xffffffffffffffffULL", + "__FLT_IS_IEC_60559__=1", + "__GNUC_WIDE_EXECUTION_CHARSET_NAME=\"UTF-16LE\"", + "__INT8_TYPE__=signed char", + "__cpp_digit_separators=201309L", + "__ELF__=1", + "__XSHAL_ABI=0", + "__xtensa__=1", + "__FLT_RADIX__=2", + "__INT_LEAST16_TYPE__=short int", + "__LDBL_EPSILON__=2.2204460492503131e-16L", + "__UINTMAX_C(c)=c ## ULL", + "__FLT32X_MIN__=2.2250738585072014e-308F32x", + "__XCHAL_HAVE_DFP_SQRT=0", + "__SIG_ATOMIC_MAX__=0x7fffffff", + "__XCHAL_HAVE_MAC16=1", + "__GCC_ATOMIC_WCHAR_T_LOCK_FREE=2", + "__USER_LABEL_PREFIX__", + "__SIZEOF_PTRDIFF_T__=4", + "__XCHAL_MMU_MIN_PTE_PAGE_SIZE=1", + "__XCHAL_DCACHE_IS_WRITEBACK=0", + "__SIZEOF_LONG__=4", + "__LDBL_DIG__=15", + "__FLT64_IS_IEC_60559__=1", + "__XCHAL_MAX_INSTRUCTION_SIZE=3", + "__FLT32X_MIN_EXP__=(-1021)", + "__INT_FAST16_MAX__=0x7fffffff", + "__GCC_CONSTRUCTIVE_SIZE=32", + "__FLT64_DIG__=15", + "__UINT_FAST32_MAX__=0xffffffffU", + "__UINT_LEAST64_TYPE__=long long unsigned int", + "__FLT_HAS_QUIET_NAN__=1", + "__FLT_MAX_10_EXP__=38", + "__FLT_HAS_INFINITY__=1", + "__GNUC_EXECUTION_CHARSET_NAME=\"UTF-8\"", + "__CHAR_UNSIGNED__=1", + "__cpp_unicode_literals=200710L", + "__UINT_FAST16_TYPE__=unsigned int", + "__INT_FAST32_WIDTH__=32", + "__CHAR16_TYPE__=short unsigned int", + "__PRAGMA_REDEFINE_EXTNAME=1", + "__SIZE_WIDTH__=32", + "__INT_LEAST16_MAX__=0x7fff", + "__INT64_MAX__=0x7fffffffffffffffLL", + "__FLT32_DENORM_MIN__=1.4012984643248171e-45F32", + "__SIG_ATOMIC_WIDTH__=32", + "__INT_LEAST64_TYPE__=long long int", + "__INT16_TYPE__=short int", + "__INT_LEAST8_TYPE__=signed char", + "__cpp_structured_bindings=201606L", + "__INT_FAST8_MAX__=0x7fffffff", + "__INTPTR_MAX__=0x7fffffff", + "__cpp_sized_deallocation=201309L", + "__cpp_guaranteed_copy_elision=201606L", + "__FLT64_HAS_QUIET_NAN__=1", + "__FLT32_MIN_10_EXP__=(-37)", + "__EXCEPTIONS=1", + "__UINT16_C(c)=c", + "__XCHAL_M_STAGE=3", + "__PTRDIFF_WIDTH__=32", + "__LDBL_MANT_DIG__=53", + "__cpp_range_based_for=201603L", + "__FLT64_HAS_INFINITY__=1", + "__STDCPP_DEFAULT_NEW_ALIGNMENT__=8", + "__SIG_ATOMIC_MIN__=(-__SIG_ATOMIC_MAX__ - 1)", + "__XCHAL_ICACHE_SIZE=0", + "__cpp_nontype_template_args=201411L", + "__INTPTR_TYPE__=int", + "__UINT16_TYPE__=short unsigned int", + "__WCHAR_TYPE__=short unsigned int", + "__XCHAL_HAVE_DEPBITS=0", + "__SIZEOF_FLOAT__=4", + "__UINTPTR_MAX__=0xffffffffU", + "__INT_FAST64_WIDTH__=64", + "__cpp_decltype=200707L", + "__FLT32_DECIMAL_DIG__=9", + "__INT_FAST64_MAX__=0x7fffffffffffffffLL", + "__GCC_ATOMIC_TEST_AND_SET_TRUEVAL=1", + "__FLT_NORM_MAX__=3.4028234663852886e+38F", + "__XCHAL_HAVE_DFP=0", + "__FLT32_HAS_INFINITY__=1", + "__UINT_FAST64_TYPE__=long long unsigned int", + "__cpp_inline_variables=201606L", + "__INT_MAX__=0x7fffffff", + "__XCHAL_HAVE_EXCLUSIVE=0", + "__STDCPP_THREADS__=1", + "__INT64_TYPE__=long long int", + "__XCHAL_HAVE_DFP_DIV=0", + "__FLT_MAX_EXP__=128", + "__XCHAL_INST_FETCH_WIDTH=4", + "__DBL_MANT_DIG__=53", + "__cpp_inheriting_constructors=201511L", + "__INT_LEAST64_MAX__=0x7fffffffffffffffLL", + "__FP_FAST_FMAF32=1", + "__WINT_TYPE__=unsigned int", + "__UINT_LEAST32_TYPE__=long unsigned int", + "__SIZEOF_SHORT__=2", + "__FLT32_NORM_MAX__=3.4028234663852886e+38F32", + "__LDBL_MIN_EXP__=(-1021)", + "__XCHAL_HAVE_S32C1I=1", + "__FLT64_MAX__=1.7976931348623157e+308F64", + "__WINT_WIDTH__=32", + "__cpp_template_auto=201606L", + "__INT_LEAST64_WIDTH__=64", + "__FLT32X_MAX_10_EXP__=308", + "__cpp_namespace_attributes=201411L", + "__WCHAR_UNSIGNED__=1", + "__LDBL_MAX_10_EXP__=308", + "__ATOMIC_RELAXED=0", + "__DBL_EPSILON__=double(2.2204460492503131e-16L)", + "__XCHAL_HAVE_SEXT=1", + "__INT_LEAST32_TYPE__=long int", + "__XTENSA_WINDOWED_ABI__=1", + "__UINT8_C(c)=c", + "__FLT64_MAX_EXP__=1024", + "__SIZEOF_WCHAR_T__=2", + "__XCHAL_HAVE_FP_POSTINC=1", + "__FLT64_NORM_MAX__=1.7976931348623157e+308F64", + "__INTMAX_MAX__=0x7fffffffffffffffLL", + "__INT_FAST8_TYPE__=int", + "__XCHAL_HAVE_MUL32_HIGH=1", + "__GNUC_STDC_INLINE__=1", + "__FLT64_HAS_DENORM__=1", + "__FLT32_EPSILON__=1.1920928955078125e-7F32", + "__DBL_DECIMAL_DIG__=17", + "__STDC_UTF_32__=1", + "__XCHAL_HAVE_FP_DIV=1", + "__INT_FAST8_WIDTH__=32", + "__FLT32X_MAX__=1.7976931348623157e+308F32x", + "__DBL_NORM_MAX__=double(1.7976931348623157e+308L)", + "__BYTE_ORDER__=__ORDER_LITTLE_ENDIAN__", + "__GCC_DESTRUCTIVE_SIZE=32", + "__XTENSA__=1", + "__INTMAX_WIDTH__=64", + "__ORDER_BIG_ENDIAN__=4321", + "__XTHAL_ABI_CALL0=1", + "__cpp_runtime_arrays=198712L", + "__FLT32_DIG__=6", + "__UINT64_TYPE__=long long unsigned int", + "__UINT32_C(c)=c ## UL", + "__cpp_alias_templates=200704L", + "__FLT_DENORM_MIN__=1.4012984643248171e-45F", + "__INT8_MAX__=0x7f", + "__LONG_WIDTH__=32", + "__UINT_FAST32_TYPE__=unsigned int", + "__FLT32X_NORM_MAX__=1.7976931348623157e+308F32x", + "__CHAR32_TYPE__=long unsigned int", + "__FLT_MAX__=3.4028234663852886e+38F", + "__cpp_constexpr=201603L", + "__XCHAL_HAVE_FP_RSQRT=1", + "__INT32_TYPE__=long int", + "__SIZEOF_DOUBLE__=8", + "__cpp_exceptions=199711L", + "__FLT_MIN_10_EXP__=(-37)", + "__FLT64_MIN__=2.2250738585072014e-308F64", + "__INT_LEAST32_WIDTH__=32", + "__INTMAX_TYPE__=long long int", + "__XCHAL_HAVE_ABS=1", + "__FLT32X_HAS_QUIET_NAN__=1", + "__ATOMIC_CONSUME=1", + "__XCHAL_NUM_DBREAK=2", + "__XCHAL_HAVE_WIDE_BRANCHES=0", + "__GNUC_MINOR__=2", + "__INT_FAST16_WIDTH__=32", + "__UINTMAX_MAX__=0xffffffffffffffffULL", + "__FLT32X_DENORM_MIN__=4.9406564584124654e-324F32x", + "__cpp_template_template_args=201611L", + "__DBL_MAX_10_EXP__=308", + "__LDBL_DENORM_MIN__=4.9406564584124654e-324L", + "__INT16_C(c)=c", + "__STDC__=1", + "__PTRDIFF_TYPE__=int", + "__LONG_MAX__=0x7fffffffL", + "__XCHAL_HAVE_FP_SQRT=1", + "__UINT32_TYPE__=long unsigned int", + "__FLT32X_MIN_10_EXP__=(-307)", + "__UINTPTR_TYPE__=unsigned int", + "__LDBL_MIN_10_EXP__=(-307)", + "__cpp_generic_lambdas=201304L", + "__SIZEOF_LONG_LONG__=8", + "__cpp_user_defined_literals=200809L", + "__GCC_ATOMIC_LLONG_LOCK_FREE=1", + "__FLT_DECIMAL_DIG__=9", + "__UINT_FAST16_MAX__=0xffffffffU", + "__LDBL_NORM_MAX__=1.7976931348623157e+308L", + "__GCC_ATOMIC_SHORT_LOCK_FREE=2", + "__XCHAL_HAVE_BE=0", + "__UINT_FAST8_TYPE__=unsigned int", + "__cpp_init_captures=201304L", + "__ATOMIC_ACQ_REL=4", + "__ATOMIC_RELEASE=3", + "USBCON" + ] + } + ] +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0448383 --- /dev/null +++ b/README.md @@ -0,0 +1,76 @@ +# Smart Fish Feeder (ESP32 + MQTT) + +An automated aquarium feeder system based on the ESP32. It dispenses food via a motor pulse triggered by Home Assistant and continuously monitors tank temperature. + +## ⚡ Features +* **Remote Feeding:** Trigger a measured feed pulse via MQTT (`tank/feed`). +* **Temperature Monitoring:** Reports water temp every 10 seconds via MQTT (`tank/temperature`). +* **Home Assistant Integration:** Fully compatible with HA Dashboards and Automation. +* **Safe Power Design:** Optically isolated power rails (ESP32 vs Motor) to prevent brownouts. + +## 🛠 Hardware List +* **Microcontroller:** ESP32-D0WD-V3 (DevKitC) +* **Actuator:** DC Motor (3V-6V) with auger/screw mechanism +* **Switching:** N-Channel MOSFET (IRFZ44N) +* **Sensor:** DS18B20 Waterproof Temperature Sensor +* **Protection:** + * 1N5822 Schottky Diode (Flyback protection) + * 10kΩ Pull-down Resistor (Gate to GND) +* **Power:** + * USB-C (5V) for ESP32 + * External 5V/12V DC Adapter for Motor + +## 🔌 Wiring & Pinout + +**⚠️ CRITICAL:** The ESP32 and Motor Power Supply must share a **Common Ground**, but 5V lines should remain separate to prevent noise/brownouts. + +### GPIO Config +| Component | Pin | ESP32 GPIO | Notes | +| :--- | :--- | :--- | :--- | +| **MOSFET Gate** | Left Leg | **GPIO 27** | Use 10kΩ Pull-down to GND | +| **Temp Data** | Yellow Wire | **GPIO 14** | Requires 4.7kΩ Pull-up (if not on module) | + +### Circuit Diagram (MOSFET) +* **Gate (Left):** -> GPIO 27 +* **Drain (Middle):** -> Motor Negative (-) +* **Source (Right):** -> Common GND +* **Motor (+):** -> External Power 5V +* **Diode:** Across Motor Terminals (Silver stripe to +5V) + +## 💻 Firmware Configuration + +**Dependencies (Arduino IDE):** +* `PubSubClient` (Nick O'Leary) +* `OneWire` +* `DallasTemperature` + +**Setup:** +1. Update `ssid`, `pass`, and `mqtt_server` in `fish_feeder.ino`. +2. Set `MOTOR_PIN` (Default: 27) and `TEMP_PIN` (Default: 14). +3. Upload. + +## 🏠 Home Assistant Integration + +### 1. Manual Configuration (YAML) +Add to `configuration.yaml` to create entities: + +```yaml +mqtt: + sensor: + - name: "Fish Tank Temperature" + state_topic: "tank/temperature" + unit_of_measurement: "°C" + device_class: temperature + unique_id: "fishtank_temp_01" + + button: + - name: "Feed Fish" + command_topic: "tank/feed" + payload_press: "pulse" + icon: mdi:fish + unique_id: "fishtank_feed_btn" +``` + +### 2. Dashboard (Lovelace) +* **Temperature:** Use a `Gauge` card linked to `sensor.fish_tank_temperature`. +* **Feeder:** diff --git a/fish_feeder.ino b/fish_feeder.ino new file mode 100644 index 0000000..f3c6b24 --- /dev/null +++ b/fish_feeder.ino @@ -0,0 +1,126 @@ +// fish_feeder_final_fixed.ino +#include +#include +#include +#include + +// --- PIN DEFINITIONS --- +#define TEMP_PIN 14 // Signal wire from DS18B20 +#define MOTOR_PIN 2 // Gate of MOSFET (Also the Blue LED) + +// --- NETWORK SETTINGS --- +const char* ssid = "Aussie Broadband 8729"; +const char* pass = "Ffdfmunfca"; +const char* mqtt_server = "192.168.20.30"; + +WiFiClient net; +PubSubClient mqtt(net); +OneWire oneWire(TEMP_PIN); +DallasTemperature sensors(&oneWire); + +void setup() { + Serial.begin(115200); + + // 1. Setup Motor (Safety First) + pinMode(MOTOR_PIN, OUTPUT); + digitalWrite(MOTOR_PIN, LOW); // Ensure motor is OFF + + // 2. Setup Sensor + sensors.begin(); + sensors.setWaitForConversion(false); + + Serial.println("--------------------------------"); + Serial.println("🔌 System Start"); + + // 3. Connect WiFi + Serial.print("📶 Connecting to WiFi..."); + WiFi.begin(ssid, pass); + + int attempts = 0; + while (WiFi.status() != WL_CONNECTED) { + delay(500); + Serial.print("."); + attempts++; + if(attempts > 20) { + Serial.println("\n❌ WiFi Failed! Check credentials."); + break; + } + } + + if (WiFi.status() == WL_CONNECTED) { + Serial.printf("\n✅ WiFi Connected! IP: %s\n", WiFi.localIP().toString().c_str()); + } + + // 4. Setup MQTT + mqtt.setServer(mqtt_server, 1883); + mqtt.setCallback([](char* topic, byte* payload, unsigned int len) { + Serial.println("⚡ MQTT Message Received!"); + triggerFeed(); // Run the feed function + }); + + Serial.println("✅ System Ready. Type 'pulse' in Serial Monitor to test."); +} + +// Separate function to handle the motor logic +void triggerFeed() { + Serial.println("⚡ Feeding Fish..."); + digitalWrite(MOTOR_PIN, HIGH); + delay(500); // Run motor for 0.5 seconds + digitalWrite(MOTOR_PIN, LOW); + Serial.println("✅ Feed Cycle Complete"); +} + +void loop() { + // 1. Maintain MQTT + if (WiFi.status() == WL_CONNECTED && !mqtt.connected()) { + if (mqtt.connect("fish-feeder", "mqtt-user", "sam4jo")) { + Serial.println("🔌 MQTT Reconnected"); + mqtt.subscribe("tank/feed"); + const char* discovery_topic = "homeassistant/sensor/fishtank_temp/config"; + const char* payload = + "{" + "\"name\": \"Fish Tank Temp\"," + "\"state_topic\": \"tank/temperature\"," + "\"unit_of_measurement\": \"°C\"," + "\"device_class\": \"temperature\"," + "\"unique_id\": \"fishtank_temp_auto\"" + "}"; + + // Publish with 'true' for Retain (so HA sees it even after restart) + mqtt.publish(discovery_topic, payload, true); + // ---------------------------------------------------- + + } else { + Serial.print("failed, rc="); + Serial.print(mqtt.state()); + Serial.println(" try again in 5 seconds"); + delay(5000); + } + } + mqtt.loop(); + + // 2. LISTEN FOR SERIAL COMMANDS (This was missing) + if (Serial.available()) { + String cmd = Serial.readStringUntil('\n'); + cmd.trim(); // Remove spaces/enter keys + if (cmd == "pulse") { + triggerFeed(); + } + } + + // 3. Temperature Logic + static unsigned long lastTemp = 0; + if (millis() - lastTemp > 60000) { // Every 10 seconds + sensors.requestTemperatures(); + float t = sensors.getTempCByIndex(0); + + Serial.printf("🌡️ Temp: %.2f°C\n", t); + + if (mqtt.connected() && t > -100) { + char buf[10]; + snprintf(buf, sizeof(buf), "%.2f", t); + mqtt.publish("tank/temperature", buf); + } + lastTemp = millis(); + } +} \ No newline at end of file