├── LICENSE.txt ├── README.md ├── case └── cap-sensor-case.scad ├── code ├── .gitignore ├── .travis.yml ├── lib │ └── readme.txt ├── platformio.ini └── src │ ├── config.h │ └── main.cpp └── pcb ├── cap-soil-sensor-cache.lib ├── cap-soil-sensor-rescue.lib ├── cap-soil-sensor.bak ├── cap-soil-sensor.csv ├── cap-soil-sensor.kicad_pcb ├── cap-soil-sensor.kicad_pcb-bak ├── cap-soil-sensor.net ├── cap-soil-sensor.png ├── cap-soil-sensor.pro ├── cap-soil-sensor.sch ├── cap-soil-sensor.xml └── schematic.pdf /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License 2 | 3 | By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. 4 | 5 | Section 1 – Definitions. 6 | 7 | Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. 8 | Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. 9 | BY-NC-SA Compatible License means a license listed at creativecommons.org/compatiblelicenses, approved by Creative Commons as essentially the equivalent of this Public License. 10 | Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. 11 | Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. 12 | Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. 13 | License Elements means the license attributes listed in the name of a Creative Commons Public License. The License Elements of this Public License are Attribution, NonCommercial, and ShareAlike. 14 | Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. 15 | Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. 16 | Licensor means the individual(s) or entity(ies) granting rights under this Public License. 17 | NonCommercial means not primarily intended for or directed towards commercial advantage or monetary compensation. For purposes of this Public License, the exchange of the Licensed Material for other material subject to Copyright and Similar Rights by digital file-sharing or similar means is NonCommercial provided there is no payment of monetary compensation in connection with the exchange. 18 | Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. 19 | Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. 20 | You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. 21 | 22 | Section 2 – Scope. 23 | 24 | License grant. 25 | Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: 26 | reproduce and Share the Licensed Material, in whole or in part, for NonCommercial purposes only; and 27 | produce, reproduce, and Share Adapted Material for NonCommercial purposes only. 28 | Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. 29 | Term. The term of this Public License is specified in Section 6(a). 30 | Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. 31 | Downstream recipients. 32 | Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. 33 | Additional offer from the Licensor – Adapted Material. Every recipient of Adapted Material from You automatically receives an offer from the Licensor to exercise the Licensed Rights in the Adapted Material under the conditions of the Adapter’s License You apply. 34 | No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. 35 | No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). 36 | 37 | Other rights. 38 | Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. 39 | Patent and trademark rights are not licensed under this Public License. 40 | To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties, including when the Licensed Material is used other than for NonCommercial purposes. 41 | 42 | Section 3 – License Conditions. 43 | 44 | Your exercise of the Licensed Rights is expressly made subject to the following conditions. 45 | 46 | Attribution. 47 | 48 | If You Share the Licensed Material (including in modified form), You must: 49 | retain the following if it is supplied by the Licensor with the Licensed Material: 50 | identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); 51 | a copyright notice; 52 | a notice that refers to this Public License; 53 | a notice that refers to the disclaimer of warranties; 54 | a URI or hyperlink to the Licensed Material to the extent reasonably practicable; 55 | indicate if You modified the Licensed Material and retain an indication of any previous modifications; and 56 | indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. 57 | You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. 58 | If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. 59 | ShareAlike. 60 | 61 | In addition to the conditions in Section 3(a), if You Share Adapted Material You produce, the following conditions also apply. 62 | The Adapter’s License You apply must be a Creative Commons license with the same License Elements, this version or later, or a BY-NC-SA Compatible License. 63 | You must include the text of, or the URI or hyperlink to, the Adapter's License You apply. You may satisfy this condition in any reasonable manner based on the medium, means, and context in which You Share Adapted Material. 64 | You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, Adapted Material that restrict exercise of the rights granted under the Adapter's License You apply. 65 | 66 | Section 4 – Sui Generis Database Rights. 67 | 68 | Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: 69 | 70 | for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database for NonCommercial purposes only; 71 | if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material, including for purposes of Section 3(b); and 72 | You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. 73 | 74 | For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. 75 | 76 | Section 5 – Disclaimer of Warranties and Limitation of Liability. 77 | 78 | Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. 79 | To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. 80 | 81 | The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. 82 | 83 | Section 6 – Term and Termination. 84 | 85 | This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. 86 | 87 | Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: 88 | automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or 89 | upon express reinstatement by the Licensor. 90 | For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. 91 | For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. 92 | Sections 1, 5, 6, 7, and 8 survive termination of this Public License. 93 | 94 | Section 7 – Other Terms and Conditions. 95 | 96 | The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. 97 | Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. 98 | 99 | Section 8 – Interpretation. 100 | 101 | For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. 102 | To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. 103 | No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. 104 | Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. 105 | 106 | Creative Commons is not a party to its public licenses. Notwithstanding, Creative Commons may elect to apply one of its public licenses to material it publishes and in those instances will be considered the “Licensor.” The text of the Creative Commons public licenses is dedicated to the public domain under the CC0 Public Domain Dedication. Except for the limited purpose of indicating that material is shared under a Creative Commons public license or as otherwise permitted by the Creative Commons policies published at creativecommons.org/policies, Creative Commons does not authorize the use of the trademark “Creative Commons” or any other trademark or logo of Creative Commons without its prior written consent including, without limitation, in connection with any unauthorized modifications to any of its public licenses or any other arrangements, understandings, or agreements concerning use of licensed material. For the avoidance of doubt, this paragraph does not form part of the public licenses. 107 | 108 | Creative Commons may be contacted at creativecommons.org. 109 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP8266 Capacitive Soil Moisture Sensor 2 | ![Image of PCB](https://github.com/theopensourcerer/esp8266-cap-soil-sensor/blob/master/pcb/cap-soil-sensor.png) 3 | ## Table of Contents 4 | * [Summary](#summary) 5 | * [Hardware](#hardware) 6 | * [Case](#case) 7 | * [Code](#code) 8 | * [Licenses](#licenses) 9 | 10 | ## Summary 11 | This is a personal project to build a Capacitive Soil Moisture Sensor for my hobby of growing chillies. 12 | 13 | The project consists of three parts: the hardware (PCB and Sensor(s) etc.(, the case to hold the sensor, and the software. 14 | 15 | I wanted to design and build my own sensors with built in WiFi so they could operate "standalone" in my tunnel. I wanted them to run from a decent capacity battery such as an 18650 Li-ion and to be able to report back information at timely intervals to my home server and database. Ultimately I want to use this information to be able to automate the watering of my plants. 16 | 17 | The Internet is a wonderful thing. I have spent many dark and long evenings through the 2016/17 winter, learning, reading and searching for information on Capacitive moisture sensors. There are numerous resources (and individual people behind each of them) I would like to thank for taking the time to design, document and discuss the various mechanisms for capacitive moisture measurement. Hopefully my own small contributions may help others in the future. 18 | 19 | Why use capacitive sensors? 20 | 21 | * The cheap and traditional moisture sensor uses a resistive technique. That is, to put it simply, the probe usually consists of two electrically conductive "prongs" which are inserted into the soil with a known gap between them. As the moisture increases, the electrical resistance decreases. This technique works but is not ideal mostly due to electrolysis [1]. Essentially the probes deteriorate rapidly due to this phenomenom and hence the measurements also change and the probes need to be replaced quite frequently 22 | 23 | * The resitive appraoch requires significantly more power (electric current) to operate than the capacitive technique, so battery life would be constrained 24 | 25 | * The fundamental principle of the capacitive sensor is that you measure the time it takes for your capacitor (the probe) to charge. This charging period changes proportionately to the moisture level of the soil. It means there is no direct electrical contact between the soil and the probe (it is insulated) therefore should last a great deal longer 26 | 27 | * It is harder to do; hence far more interesting to design and produce ;-) 28 | 29 | Below is my list, in no particular order, of the online resources I found to be most helpful during my research (there were and are others; Google is your friend): 30 | 31 | http://pcb.daince.net/doku.php?id=sensor_soil_2 32 | http://zerocharactersleft.blogspot.co.uk/2011/11/pcb-as-capacitive-soil-moisture-sensor.html 33 | 34 | https://www.dfrobot.com/wiki/index.php/Capacitive_Soil_Moisture_Sensor_SKU:SEN0193 (Bought one of these to test. It works) 35 | https://github.com/Miceuz/i2c-moisture-sensor 36 | and 37 | https://wemakethings.net/chirp/ (Bought one of these - this works too) 38 | 39 | http://www.instructables.com/id/Comparison-of-Capacitive-Soil-Probes/ 40 | and then 41 | https://github.com/acolomitchi/cap-soil-moisture-v2 (I have used this probe design. Thanks acolomitchi) 42 | 43 | Then I came across these few resources (thank you Google Translate) 44 | * https://www.mikrocontroller.net/topic/335407 45 | 46 | Which led me here: 47 | * http://shop.thomasheldt.de/product_info.php?info=p90_giess-o-mat-sensor-kit.html (Bought a couple of these and they work) 48 | 49 | Which then led me to: 50 | * https://github.com/Zentris/erdfeuchtemessung 51 | 52 | and 53 | * https://github.com/lh84/moisture_sensor_esp12 54 | 55 | I have also been following along with this project: 56 | * https://luckyresistor.me/2017/02/08/how-to-design-a-cheap-plant-watering-sensor-part-1/ 57 | I really like the way this project has been analysed, designed and documented - much more so than mine which is a "try-something-and-see-if-it-works" approach. 58 | 59 | These resources above gave me confidence that a custom design was possible so I set to work basing the Schematic and PCB on the work of the people above. The use of a Schmitt Trigger Inverter to "square" up the oscillations of the sensor probe means it can be read by pretty much any GPIO as long as the MCU is fast enough. The ESP8266 has some limitations in this regard so I considered using a half-wave rectifier to convert this to a simple analogue voltage but the work of Zentris and Lars(lh84) convinced me that the ESP8266 was capable of reading the frequency directly if it can be kept below about 150Khz. 60 | 61 | This is _all_ still very much a work in progress. I have built a prototype board and have had it running on my desk but the results leave me rather confused :-( 62 | 63 | 64 | ## Hardware 65 | The Schematic and PCB are designed in KiCAD. A version of this board has been fabricated but it is not the final version. Probably the most interesting part is the layout of the probe footprint itself. This came from acolomitchi as mentioned above. (I have modified the layout somewhat so it is more suited to an integrated PCB - I also made it a little longer as my target was for quite large pots). 66 | 67 | 68 | ## Case 69 | The case is designed in OpenSCAD and is suitable for printing on a 3D Printer. The basic idea is that the PCB slides into the case. The PCB has about 1.5mm of empty space down each side of the board which should be enough to slot in place. The probe end of the PCB fits through the slot in the bottom of the case. There should be enough height to support the power connector (not tested) and the other half of the case holds an 18650 battery in a plastic holder. The "lid" screws on and has protrusions which should prevent the probe PCB and the battery from moving about too much. I plan to use something like silicon bathrooom sealant around the probe slot to prevent any moisture ingressing into the case. Please feel free to use and improve - within the terms of the license of course. 70 | 71 | 72 | ## Code 73 | The software for the ESP8266 is in this directory. It should be fairly simple C code. The config.h file contains user-defined parameters. The ESP8266 code works like this: On power up the ESP attempts to connect to the WiFi network. If successful it then attempts to read the frequency of the capacitive sensor probe. If the Sensor probe is read successfully the data is formatted as a JSON object and sent to the MQTT broker. The ESP8266 also sends information about its supply voltage and the time it took to run this code loop. Finally the code puts the ESP into "Deep Sleep" for a preconfigured period. 74 | 75 | 76 | ## Licenses 77 | * The software is GPL (http://www.gnu.org/licenses/) 78 | * The OpenSCAD case design, and the Schematic and PCB are Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International Public License (https://creativecommons.org/licenses/by-nc-sa/4.0/) 79 | 80 | 81 | [1] https://en.wikipedia.org/wiki/Electrolysis 82 | -------------------------------------------------------------------------------- /case/cap-sensor-case.scad: -------------------------------------------------------------------------------- 1 | /** 2 | * Case for Capacitive Soil Sensors 3 | * 4 | * License: Creative Commons Attribution-ShareAlike 4.0 International 5 | * Copyright 2017 Alan Lord 6 | **/ 7 | $fn = 50; 8 | 9 | l = 80; 10 | w = 35; 11 | h = 43; 12 | 13 | prbw = 17; 14 | prbd = 2; 15 | 16 | wall = 2; 17 | 18 | nutSize = 6; 19 | nutHeight = 3; 20 | nutThread = 3.2; 21 | boltLength = 8; 22 | fix=8; 23 | 24 | pcbw = 29.5; 25 | pcbh = 52.5; 26 | pcbpad = 6.5; 27 | 28 | pcbwctrs = 20.320; 29 | pcbdctrs = 51.435; 30 | 31 | sloth=((w-pcbw)/2)+1.5; 32 | 33 | slotDepthFromTop = 15; 34 | 35 | // Display the box 36 | box(); 37 | 38 | // Display the lid 39 | %lid(); 40 | 41 | module box() { 42 | %difference() { // The % makes the external wall transparent ot invisibble 43 | roundedCube(h+wall*2,w+wall*2,l+wall,nutThread); 44 | translate([wall,wall,wall]) { 45 | roundedCube(h,w,l,nutThread); 46 | } 47 | translate([slotDepthFromTop,((w+wall*2)-prbw)/2,0]) { 48 | cube([prbd,prbw,wall*2]); 49 | } 50 | } 51 | translate([slotDepthFromTop-wall,wall,wall]) { 52 | pcbSlot(pcbh); 53 | } 54 | translate([slotDepthFromTop-wall,w+wall-sloth,wall]) { 55 | pcbSlot(pcbh); 56 | } 57 | translate([slotDepthFromTop+wall*3,wall,wall]) { 58 | cube([1,w,l-wall*2]); 59 | } 60 | fixing(); 61 | translate([0,(w+wall*2)-fix,0]) { 62 | fixing(); 63 | } 64 | translate([(h+wall*2)-fix,(w+wall*2)-fix,0]) { 65 | fixing(); 66 | } 67 | translate([(h+wall*2)-fix,0,0]) { 68 | fixing(); 69 | } 70 | 71 | x=(h-22+wall); 72 | y=((w+wall*2)-21)/2; 73 | translate([x,y,wall]) { 74 | battery(); 75 | } 76 | } 77 | 78 | 79 | module lid() { 80 | xtrns = nutHeight+wall+8.5; 81 | difference(){ 82 | translate([0,0,l+wall]) { 83 | roundedCube(h+wall*2,w+wall*2,wall,nutThread); 84 | } 85 | translate([fix/2,fix/2,l+wall]) { 86 | cylinder(d=nutThread,h=wall); 87 | } 88 | translate([(h+wall*2)-fix/2,fix/2,l+wall]) { 89 | cylinder(d=nutThread,h=wall); 90 | } 91 | translate([(h+wall*2)-fix/2,(w+wall*2)-fix/2,l+wall]) { 92 | cylinder(d=nutThread,h=wall); 93 | } 94 | translate([fix/2,(w+wall*2)-fix/2,l+wall]) { 95 | cylinder(d=nutThread,h=wall); 96 | } 97 | } 98 | sloth=l-(pcbh+pcbpad)-1; 99 | translate([slotDepthFromTop-wall,((w+wall*2)-w)/2,l-sloth+wall]) { 100 | difference() { 101 | cube([wall*3,w,sloth]); 102 | translate([0,w/2,0]) { 103 | rotate([90,0,90]) cylinder(h=wall*3,d=5); 104 | } 105 | } 106 | } 107 | translate([h-10,(w+wall*2)/2,(l+wall)-3]) { 108 | cylinder(h=3,d=10); 109 | } 110 | 111 | } 112 | 113 | module bolt(width,height,thread,length,hull) { 114 | cylinder(d=width/(cos(180/6)), h=height, $fn=6); 115 | if(hull) { 116 | hull(){ 117 | translate([0,0,height]) { 118 | cylinder(d=thread,h=length); 119 | } 120 | translate([thread,0,height]) { 121 | cylinder(d=thread,h=length); 122 | } 123 | } 124 | } else { 125 | translate([0,0,height]) { 126 | cylinder(d=thread,h=length); 127 | } 128 | } 129 | } 130 | 131 | module fixing() { 132 | difference() { 133 | translate([0,0,wall]){ 134 | roundedCube(fix,fix,l,nutThread); 135 | } 136 | translate([fix/2,fix/2,l-(boltLength-wall)]) { 137 | cylinder(d=nutThread,h=boltLength); 138 | } 139 | } 140 | } 141 | 142 | module battery() { 143 | l=76; 144 | w=21; 145 | h=22; 146 | cube([h,w,l]); 147 | } 148 | 149 | module pcbSlot(l) { 150 | cube([wall,sloth,l+pcbpad]); 151 | translate([wall*2,0,0]) { 152 | cube([wall,sloth,l+pcbpad]); 153 | } 154 | translate([wall,0,0]) { 155 | cube([prbd,sloth,pcbpad]); 156 | } 157 | } 158 | 159 | module roundedCube(xdim,ydim,zdim,rdim) { 160 | hull() { 161 | translate([rdim,rdim,0]) cylinder(r=rdim,h=zdim); 162 | translate([xdim-rdim,rdim,0]) cylinder(r=rdim,h=zdim); 163 | translate([rdim,ydim-rdim,0]) cylinder(r=rdim,h=zdim); 164 | translate([xdim-rdim,ydim-rdim,0]) cylinder(r=rdim,h=zdim); 165 | } 166 | } -------------------------------------------------------------------------------- /code/.gitignore: -------------------------------------------------------------------------------- 1 | .pioenvs 2 | .piolibdeps 3 | .clang_complete 4 | .gcc-flags.json 5 | -------------------------------------------------------------------------------- /code/.travis.yml: -------------------------------------------------------------------------------- 1 | # Continuous Integration (CI) is the practice, in software 2 | # engineering, of merging all developer working copies with a shared mainline 3 | # several times a day < http://docs.platformio.org/page/ci/index.html > 4 | # 5 | # Documentation: 6 | # 7 | # * Travis CI Embedded Builds with PlatformIO 8 | # < https://docs.travis-ci.com/user/integration/platformio/ > 9 | # 10 | # * PlatformIO integration with Travis CI 11 | # < http://docs.platformio.org/page/ci/travis.html > 12 | # 13 | # * User Guide for `platformio ci` command 14 | # < http://docs.platformio.org/page/userguide/cmd_ci.html > 15 | # 16 | # 17 | # Please choice one of the following templates (proposed below) and uncomment 18 | # it (remove "# " before each line) or use own configuration according to the 19 | # Travis CI documentation (see above). 20 | # 21 | 22 | 23 | # 24 | # Template #1: General project. Test it using existing `platformio.ini`. 25 | # 26 | 27 | # language: python 28 | # python: 29 | # - "2.7" 30 | # 31 | # sudo: false 32 | # cache: 33 | # directories: 34 | # - "~/.platformio" 35 | # 36 | # install: 37 | # - pip install -U platformio 38 | # 39 | # script: 40 | # - platformio run 41 | 42 | 43 | # 44 | # Template #2: The project is intended to by used as a library with examples 45 | # 46 | 47 | # language: python 48 | # python: 49 | # - "2.7" 50 | # 51 | # sudo: false 52 | # cache: 53 | # directories: 54 | # - "~/.platformio" 55 | # 56 | # env: 57 | # - PLATFORMIO_CI_SRC=path/to/test/file.c 58 | # - PLATFORMIO_CI_SRC=examples/file.ino 59 | # - PLATFORMIO_CI_SRC=path/to/test/directory 60 | # 61 | # install: 62 | # - pip install -U platformio 63 | # 64 | # script: 65 | # - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N 66 | -------------------------------------------------------------------------------- /code/lib/readme.txt: -------------------------------------------------------------------------------- 1 | 2 | This directory is intended for the project specific (private) libraries. 3 | PlatformIO will compile them to static libraries and link to executable file. 4 | 5 | The source code of each library should be placed in separate directory, like 6 | "lib/private_lib/[here are source files]". 7 | 8 | For example, see how can be organized `Foo` and `Bar` libraries: 9 | 10 | |--lib 11 | | |--Bar 12 | | | |--docs 13 | | | |--examples 14 | | | |--src 15 | | | |- Bar.c 16 | | | |- Bar.h 17 | | |--Foo 18 | | | |- Foo.c 19 | | | |- Foo.h 20 | | |- readme.txt --> THIS FILE 21 | |- platformio.ini 22 | |--src 23 | |- main.c 24 | 25 | Then in `src/main.c` you should use: 26 | 27 | #include 28 | #include 29 | 30 | // rest H/C/CPP code 31 | 32 | PlatformIO will find your libraries automatically, configure preprocessor's 33 | include paths and build them. 34 | 35 | More information about PlatformIO Library Dependency Finder 36 | - http://docs.platformio.org/page/librarymanager/ldf.html 37 | -------------------------------------------------------------------------------- /code/platformio.ini: -------------------------------------------------------------------------------- 1 | ; PlatformIO Project Configuration File 2 | ; 3 | ; Build options: build flags, source filter 4 | ; Upload options: custom upload port, speed and extra flags 5 | ; Library options: dependencies, extra library storages 6 | ; Advanced options: extra scripting 7 | ; 8 | ; Please visit documentation for the other options and examples 9 | ; http://docs.platformio.org/page/projectconf.html 10 | 11 | [env:esp12e] 12 | platform = espressif8266 13 | board = esp12e 14 | framework = arduino 15 | 16 | -------------------------------------------------------------------------------- /code/src/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | Capacitive Soil Moisture Sensor 3 | 4 | For the Espressif ESP8266 5 | 6 | Uses MQTT and custom PCB Sensor to read and transmit a frequency to an MQTT 7 | Broker. The Frequency varies depending on the moisture level of the medium 8 | surrounding the probe. 9 | 10 | This code was written and tested using the PlatformIO IDE and the ESP8266-12F 11 | module. 12 | 13 | Ideas and code from various sources: 14 | https://github.com/acolomitchi/cap-soil-moisture-v2 15 | https://github.com/Zentris/erdfeuchtemessung 16 | https://github.com/lh84/moisture_sensor_esp12 17 | 18 | This program is free software: you can redistribute it and/or modify 19 | it under the terms of the GNU General Public License as published by 20 | the Free Software Foundation, either version 3 of the License, or 21 | (at your option) any later version. 22 | 23 | This program is distributed in the hope that it will be useful, 24 | but WITHOUT ANY WARRANTY; without even the implied warranty of 25 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 26 | GNU General Public License for more details. 27 | You should have received a copy of the GNU General Public License 28 | along with this program. If not, see . 29 | 30 | This code is licensed under the GNU GPL and is open for ditrbution 31 | and copying in accordance with the license. 32 | This header must be included in any derived code or copies of the code. 33 | 34 | (C) Alan Lord 2017 35 | */ 36 | 37 | // Debugging 38 | #define DEBUG_PRINT 1 39 | 40 | // Change these to suit your own application and network. 41 | const char* WIFI_SSID = ""; 42 | const char* WIFI_PASSWORD = ""; 43 | const char* MQTT_SERVER = "192.168.1.2"; 44 | 45 | // SensorName 46 | const char* SENSORNAME = "soilpot1"; 47 | 48 | // Topic 49 | const char* TOPIC = "PT/Soil"; 50 | 51 | // Deep Sleep (uSec) Debug = 10000000 (10 Seconds). Production: 3600000000 (1 hour) 52 | long deep_sleep = 10000000; 53 | 54 | // Timout if WiFi doesn't connect (15000000 = 15seconds) 55 | long WIFI_TIMEOUT = 15000000; 56 | 57 | // Deep Sleep mode. 58 | #define DS_MODE WAKE_RF_DEFAULT 59 | 60 | #define POWER_PIN 14 61 | 62 | #define SENSOR_PIN 12 63 | 64 | #define MEASURING_TIME 100 // how long a sample lasts 65 | #define MEASURING_INTERVALS 9 // how many samples are taken? 66 | -------------------------------------------------------------------------------- /code/src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | GNU GENERAL PUBLIC LICENSE 3 | Version 3, 29 June 2007 4 | This program is free software: you can redistribute it and/or modify 5 | it under the terms of the GNU General Public License as published by 6 | the Free Software Foundation, either version 3 of the License, or 7 | (at your option) any later version. 8 | This program is distributed in the hope that it will be useful, 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 | GNU General Public License for more details. 12 | You should have received a copy of the GNU General Public License 13 | along with this program. If not, see . 14 | - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 15 | 16 | Original code sources from: 17 | Erdfeuchtemessung mit ESP8266-01 / ESP8266-12(e) 18 | Measure soil moisture with ESP8266-01 / ESP8266-12(e) 19 | (2016) 20 | @Autors: 21 | - Ralf Wießner (aka Zentris) 22 | https://github.com/Zentris/erdfeuchtemessung 23 | */ 24 | #include "config.h" 25 | 26 | #include 27 | #include 28 | #include 29 | 30 | // Expose Espressif SDK functionality 31 | extern "C" { 32 | #include "user_interface.h" 33 | } 34 | 35 | // Set up ESP8266 ADC for voltage read 36 | ADC_MODE(ADC_VCC); 37 | float vcc; 38 | 39 | // Sensor average 40 | unsigned long soilMoistAveraged; 41 | 42 | volatile unsigned long counter = 0; // interrupt loop counter 43 | 44 | // Timer placeholders 45 | unsigned long startMills = 0; 46 | 47 | // Function Prototypes 48 | void readSensor(); 49 | void setup_wifi(); 50 | void reconnect(); 51 | void publishJSON(); 52 | void goingToSleep(); 53 | // End Prototypes 54 | 55 | // Begin code 56 | WiFiClient espClient; 57 | PubSubClient client(espClient); 58 | 59 | void setup() { 60 | startMills = millis(); 61 | vcc = ESP.getVcc(); 62 | Serial.begin(115200); 63 | 64 | digitalWrite(POWER_PIN, HIGH); // switch sensor power on 65 | 66 | setup_wifi(); 67 | client.setServer(MQTT_SERVER, 1883); 68 | } 69 | 70 | void setup_wifi() { 71 | // We start by connecting to a WiFi network 72 | if (DEBUG_PRINT) { 73 | Serial.println(); 74 | Serial.print("Connecting to "); 75 | Serial.println(WIFI_SSID); 76 | } 77 | WiFi.begin(WIFI_SSID, WIFI_PASSWORD); 78 | 79 | while (WiFi.status() != WL_CONNECTED) { 80 | delay(500); 81 | Serial.print("."); 82 | if (millis() - startMills > WIFI_TIMEOUT) { 83 | if (DEBUG_PRINT) { 84 | Serial.println("Taken too long to connect to WiFi. Going to sleep"); 85 | } 86 | goingToSleep(); 87 | } 88 | } 89 | 90 | if (DEBUG_PRINT) { 91 | Serial.println(""); 92 | Serial.println("WiFi connected"); 93 | Serial.println("IP address: "); 94 | Serial.println(WiFi.localIP()); 95 | } 96 | } 97 | 98 | void loop() { 99 | if (!client.connected()) { 100 | reconnect(); 101 | } 102 | 103 | readSensor(); 104 | 105 | if(soilMoistAveraged) { 106 | if (DEBUG_PRINT) { 107 | Serial.print("Read Sensor. Publish message: "); 108 | } 109 | publishJSON(); 110 | } 111 | 112 | goingToSleep(); 113 | } 114 | 115 | void reconnect() { 116 | // Loop until we're reconnected 117 | while (!client.connected()) { 118 | if (DEBUG_PRINT) { 119 | Serial.print("Attempting MQTT connection..."); 120 | } 121 | // Attempt to connect 122 | if (client.connect("CapSensor")) { 123 | if (DEBUG_PRINT) { 124 | Serial.println("Connected"); 125 | } 126 | } else { 127 | if (DEBUG_PRINT) { 128 | Serial.print("Failed to connect. State = "); 129 | Serial.print(client.state()); 130 | Serial.println(" Retry in 2 seconds"); 131 | } 132 | // Wait 2 seconds before retrying 133 | delay(2000); 134 | } 135 | } 136 | } 137 | 138 | void publishJSON() { 139 | if (client.connected()) { 140 | StaticJsonBuffer<150> jsonBuffer; 141 | JsonObject& root = jsonBuffer.createObject(); 142 | JsonArray& payload = root.createNestedArray("payload"); 143 | JsonObject& data = payload.createNestedObject(); 144 | data["sensorid"] = SENSORNAME; 145 | data["moisture"] = soilMoistAveraged; 146 | data["vcc"] = vcc/1000; 147 | data["cycletime"] = millis() - startMills; 148 | if (DEBUG_PRINT) { 149 | Serial.print("Sending payload: "); 150 | root.prettyPrintTo(Serial); 151 | } 152 | 153 | char buffer[150]; 154 | root.printTo(buffer, sizeof(buffer)); 155 | if (client.publish(TOPIC, buffer)); 156 | if (DEBUG_PRINT) { 157 | Serial.print("Published OK --> "); 158 | Serial.println(millis() - startMills); 159 | } 160 | } else { 161 | if (DEBUG_PRINT) { 162 | Serial.print("Publish failed --> "); 163 | Serial.println(millis() - startMills); 164 | } 165 | } 166 | } 167 | 168 | /** 169 | * Simple median/average calculation 170 | * ------------------------------------ 171 | * Getting array will be sorted and now get the average over the middle values 172 | */ 173 | unsigned long median(unsigned long *values, size_t arraySize) { 174 | unsigned long tmp = 0; // set to 0, make the compiler happy :-) 175 | const size_t relVal = 2; // +- 2 Werte + 1 für die Mittelwertberechnung 176 | 177 | for (size_t i=0; i < arraySize-2; i++) { 178 | for (size_t j=arraySize-1; j > i; j--) { 179 | if ( values[j] < values[j-1] ) { 180 | tmp = values[j]; 181 | values[j] = values[j-1]; 182 | values[j-1] = tmp; 183 | } 184 | } 185 | } 186 | 187 | if (DEBUG_PRINT) { 188 | for (size_t x=0; x 2 | 3 | 4 | /home/alanlord/Personal/Projects/git/esp8266-cap-soil-sensor/pcb/cap-soil-sensor.sch 5 | Tue 28 Mar 2017 19:10:00 BST 6 | Eeschema 4.0.4+e1-6308~48~ubuntu16.04.1-stable 7 | 8 | 9 | Wifi Capacitive Soil Moisture Probe 10 | Author: Alan Lord 11 | 1.0 12 | 2017-03-28 13 | cap-soil-sensor.sch 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 10uF 24 | Capacitors_SMD:C_1206_HandSoldering 25 | 26 | 27 | 588E2133 28 | 29 | 30 | 1uF 31 | Capacitors_SMD:C_1206_HandSoldering 32 | 33 | 34 | 588E215C 35 | 36 | 37 | 100 38 | Resistors_SMD:R_1206_HandSoldering 39 | 40 | 41 | 588E21F6 42 | 43 | 44 | ESP-12F 45 | ESP8266:ESP-12E 46 | 47 | 48 | 588E2247 49 | 50 | 51 | MCP1700T 52 | TO_SOT_Packages_SMD:SOT-23_Handsoldering 53 | 54 | IC MICROCHIP MCP1700T-vv02E/TT 55 | 56 | 57 | 58 | 588E2DAE 59 | 60 | 61 | PWR 62 | Connectors_JST:JST_XH_B02B-XH-A_02x2.50mm_Straight 63 | 64 | 65 | 5893A688 66 | 67 | 68 | SERIAL 69 | Pin_Headers:Pin_Header_Straight_1x05_Pitch2.54mm 70 | 71 | 72 | 58A2FBB1 73 | 74 | 75 | 10k 76 | Resistors_SMD:R_1206_HandSoldering 77 | 78 | 79 | 58A321F5 80 | 81 | 82 | 10k 83 | Resistors_SMD:R_1206_HandSoldering 84 | 85 | 86 | 58A3223E 87 | 88 | 89 | 10k 90 | Resistors_SMD:R_1206_HandSoldering 91 | 92 | 93 | 58A3227D 94 | 95 | 96 | 10k 97 | Resistors_SMD:R_1206_HandSoldering 98 | 99 | 100 | 58A32A7D 101 | 102 | 103 | POT-BOURNS-3364W 104 | manuf:BOURNS-3364-W 105 | 106 | 107 | 58A2F8E1 108 | 109 | 110 | Switch_SPDT_x2 111 | switches:SW_SPDT_PCM12 112 | 113 | 114 | 58A899D1 115 | 116 | 117 | INSPECTION 118 | Pin_Headers:Pin_Header_Straight_1x01_Pitch2.54mm 119 | 120 | 121 | 58B16F68 122 | 123 | 124 | CS 125 | cap-sensor:cap_sensor_probe 126 | 127 | 128 | 58BAF5D6 129 | 130 | 131 | RESET 132 | switches:SKQGAFE010_Switch 133 | 134 | 135 | 58D67626 136 | 137 | 138 | FLASH 139 | switches:SKQGAFE010_Switch 140 | 141 | 142 | 58D676A5 143 | 144 | 145 | 74LS14 146 | KiCad/Housings_SOIC.pretty:SOIC-14_3.9x8.7mm_Pitch1.27mm 147 | 148 | 149 | 58D687CA 150 | 151 | 152 | 153 | 154 | 155 | U 156 | 74LS14-RESCUE-cap-soil-sensor 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | Unpolarized capacitor 177 | 178 | C? 179 | C_????_* 180 | C_???? 181 | SMD*_c 182 | Capacitor* 183 | 184 | 185 | C 186 | C 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | Connector 01x01 195 | 196 | Pin_Header_Straight_1X01 197 | Pin_Header_Angled_1X01 198 | Socket_Strip_Straight_1X01 199 | Socket_Strip_Angled_1X01 200 | 201 | 202 | P 203 | CONN_01X01 204 | 205 | 206 | 207 | 208 | 209 | 210 | Connector 01x02 211 | 212 | Pin_Header_Straight_1X02 213 | Pin_Header_Angled_1X02 214 | Socket_Strip_Straight_1X02 215 | Socket_Strip_Angled_1X02 216 | 217 | 218 | P 219 | CONN_01X02 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | Connector 01x05 228 | 229 | Pin_Header_Straight_1X05 230 | Pin_Header_Angled_1X05 231 | Socket_Strip_Straight_1X05 232 | Socket_Strip_Angled_1X05 233 | 234 | 235 | P 236 | CONN_01X05 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | Unpolarized capacitor 248 | 249 | C? 250 | C_????_* 251 | C_???? 252 | SMD*_c 253 | Capacitor* 254 | 255 | 256 | CS 257 | CS 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | ESP8266 ESP-12E module, 22 pins, 2mm, PCB antenna 266 | http://l0l.org.uk/2014/12/esp8266-modules-hardware-guide-gotta-catch-em-all/ 267 | 268 | ESP-12E 269 | 270 | 271 | U 272 | ESP-12E 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | Reg LDO 250mA [SOT-23] 301 | 302 | SOT-23 303 | 304 | 305 | U 306 | MCP1700T-vv02E/TT 307 | IC MICROCHIP MCP1700T-vv02E/TT 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | Pot Trim 25turn 100ppm/K [PTH] 317 | 318 | BOURNS-3296W 319 | 320 | 321 | RV 322 | POT-BOURNS-3296W 323 | manuf:BOURNS-3296W 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | Resistor 333 | 334 | R_* 335 | Resistor_* 336 | 337 | 338 | R 339 | R 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | Double Single Pole Double Throw (SPDT) switch 348 | 349 | SW 350 | Switch_SPDT_x2 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | Switch, SPST tactile 363 | 364 | SW 365 | TACT-CK-PTS645-SMD 366 | manuf:CK-PTS645-SMD 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | /home/alanlord/Personal/Projects/electronics/kicad/libraries/kicad-schlib/library/pasv-Bourns.lib 379 | 380 | 381 | /home/alanlord/Personal/Projects/electronics/kicad/libraries/kicad-schlib/library/Microchip.lib 382 | 383 | 384 | /home/alanlord/Personal/Projects/electronics/kicad/libraries/cap-sensor.lib 385 | 386 | 387 | /home/alanlord/Personal/Projects/electronics/kicad/libraries/kicad-schlib/library/electomech-misc.lib 388 | 389 | 390 | /home/alanlord/Personal/Projects/electronics/kicad/libraries/kicad-ESP8266/ESP8266.lib 391 | 392 | 393 | /home/alanlord/Personal/Projects/git/esp8266-cap-soil-sensor/pcb/cap-soil-sensor-rescue.lib 394 | 395 | 396 | /usr/share/kicad/library/conn.lib 397 | 398 | 399 | /usr/share/kicad/library/device.lib 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | -------------------------------------------------------------------------------- /pcb/schematic.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/theopensourcerer/esp8266-cap-soil-sensor/13a4ccfee8d40cb9aa3013a98b65b5067e8ecf12/pcb/schematic.pdf --------------------------------------------------------------------------------