I already have a sketch, the so-called skeleton, onto which I’m going to add the programs – our muscles. Firstly, I have connected all the necessary libraries: SPI and Ethernet libraries to work with the Ethernet shield and
QuadDisplay library to work with the display. I have determined all the pins, to which I am going to connect our device following the diagram: the
pump, the buzzer and the display. Two other pins are for the water detection sensor, which
we made ourselves. In fact, these are just two wires which the water will close. Next we need to connect the sensors. For soil humidity, we need to write out SOIL_PIN, for temperature — TEMP_PIN, and for lightness this’ll
be LIGHT_PIN. Then we have these macrodefinitions with the names of different states, which we also used to have in the
skeleton of our sketch. Next, I have named all the possible replies to the Web Request function. If we don’t receive any request, we will have the “No client”
reply or WEB_NO_CLIENT. If we get a request to water the plant automatically, then the reply will be
WEB_FORCED_WATERING. Finally, if this is a request to send data, we shall have this WEB_CLIMATE_REQUEST. I have also created a macrodefinition, which will store the number of
milliseconds, during which the system will be watering the plant. Thus, you can configure this information right here. I shall set a 1 sec value. There are three more settings that are responsible for threshold values, which climate parameters need to reach and exceed to create all the necessary conditions for watering. We already had this line, where we create a global variable named STATE and initialize it with STATE_STANDBY value. Finally, apart from gotWater, we have three new global variables to store climate parameters. I have made them global to simplify data transmission to the Internet. Thus, one function will be taking these readings to save them here, whereas the other function will be taking whatever has been saved in the global variable to transmit it following
the received request. Next come the lines that we saw when we were studying the process of data
transmission. This is the database with the MAC address of the Ethernet shield, IP object with our IP address, and the port number. Next we create an EthernetClient object right here. A line is created, which will store the requests. All the pins have been configured in setup. Let me mention that I have given the name INPUT_PULLUP to the pin, which will read off information about whether or not there is water left. This means that the pin is drawn to the power source. Thus, when we check for water, we will change the state of the second pin, from which we are sending the signal,
to the “low” state. Respectively, when the second pin, this WATER_OUT_PIN, is in the “low” state and it’s closed with pin WATER_IN_PIN, WATER_IN_PIN will change from the “high” to the “low” state. So here I am going to start WATER_OUT_PIN in the “high”
state and I will then switch it to “low”. Then, the Ethernet shield starts working when its server is started. We have the same things in the loop that we’ve just examined in the program skeleton. One thing I’ve done is I’ve made the display output pins’ current state. This switch structure looks exactly the same, except for 1 and 2, which I have substituted with these macrodefinitions to make the
code more comprehensible. When we reread the code in several days, it’ll be hard for us to understand what’s 1 and what’s 2. But with the help of macrodefinitions, we understand what it’s all about. Other sections have stayed unchanged. Next, we need to determine all the above-mentioned functions. The “alarm” function doesn’t return any value, and we can just call the “tone”
function in it. In other words, we could call the “tone” function in the same section where we
call the “alarm” function, but, say, we want to make our alarm more sophisticated, so our code will
be extended. Instead of extending our automate, we’d better extend the “alarm”, and everything will stay as
it is. Thus, we know that we need to call the “alarm” function and we don’t need to know what’s inside it. The “alarm” function itself will get extended if necessary. Next comes another simple function – the “watering” function. It won’t return any values, but it has a pin inside, which has the “Power key” module connected to it, into which the pump is
plugged. Let’s turn it on. Then we need to wait for some time, the duration of which is mentioned
in the WATERING_MILLIS
macrodefinition. In our case, this is 1 sec. Now let’s turn off the “Watering” function. Next, we have the CHECK_CLIMATE function definition, which checks climate parameters and returns a boolean value: true if the conditions are favorable for watering and false if they are still unfavorable. First, we need to save current readings of the analog inputs into the three global variables we mentioned before. The inputs have climate sensors connected to them: the soil humidity sensor, the temperature sensor and the light sensor. Afterwards, the system checks if these values exceed the threshold values. And if all the three parameters are true, i.d. it’s not dark, so it’s not night, it’s quite warm, so it’s not cold, and the soil is not watered enough, so it’s dry, the system will return the “true” value, which will mean that it’s time to water the plant. Alternatively, the system will return the “false” value. It’s obvious that this is the most primitive way of taking care of
your plant. You can make this CHECK_CLIMATE function more complex if you aim to create an automated greenhouse, a vegetable plot, and so on. That is if you want to make the function more complex in order to consider various
combinations of different conditions. For example, the system will water the plant at night, but not in cold weather. Or if the soil is wet and if it’s light, the system won’t water the plant in
daylight hours. Well, all can I say is that there may be various sorts of combinations. Besides, you may have even more sensors connected, so the number of combinations will only increase. And in these combinations, you can do many various things. In the end, it’ll return a “true” value if it’s time to water the plant, and the “false” value if it’s not yet time for it. Next comes the checkWater function, which checks for water, and this function will also return a boolean value. It’ll be true if there is water and false if there is no water. We shall put “low” at the beginning of WATER_OUT_PIN, and then we shall read off WATER_IN_PIN. In case there is contact between them, we will get a low value on WATER_IN_PIN. Alternatively, if there is no contact, we will get a high value. Consequently, digitalWrite will return the “true” value if there is no contact. This’ll mean that the wires are not plunged in water. In this case, we simply say that there is no water. By saying this, we assign a value to the gotWater global value. Otherwise, if the wires are plunged in water and there is contact, the system will return the “true” value. Afterwards, we shall turn off WATER_OUT_PIN, i.e. bring it to the “high” state. We will then return gotWater, regardless of its being a global value. Naturally, this is not a perfect solution, but in this case, it
is the simplest one. Besides, we’ve had the chance to remind ourselves how global variable are
different from all the other ones. WebRequest function begins next. It’ll be returning data of the integer type, since it may have several possible answers. Here we have basically copied the lines which we already had when we examined the example with the page
output. If you want, you can scroll back and take a look again at what this means. We’ve only changed one thing: now, if there is ?water substring in
the request, i.e. the incoming command to water the plant automatically, we will be returning this value hidden behind this macrodefinition. In other words, webRequest tells the system that it should start watering
automatically. Alternatively, when we’ve received the end of the line and this line turns
out to be empty, we will be returning the value hidden behind the WEB_CLIMATE_REQUEST
macrodefinition. I don’t even remember what digit it is now. Frankly speaking, I don’t really need to know it. What I know is that in the automate we are going to get a request to output data in the network. [SCROLLS DOWN] In case we don’t receive a request, but the function has already been called, we will consider that there is no client. [SCROLLS DOWN] Last but not least, We have the sendPage function, which does not return any values either. We have copied some fragments from the example with the page output in
it, which appear in the “Send Page” function. Everything written here we’ve already seen before. I have included some minor changes down here. Firstly, I have removed the loop, which we had in the standard sample, and in which we had the sequential output of all the values read off
at our analog inputs. Now we shall write the names of the measured parameter and the value
itself, which is stored in the corresponding global variable, concerning soil humidity, temperature and lightness. Let me remind you that this <br /> tag is a line break. There is a certain established condition at the end. If the gotWater global variable stores the “true” value, i.e. there is water in the container, we shall
write that everything is OK with the water and we shall output this link, which will allow us to start watering automatically. Conversely, if there is no water left, we shall just write that there is no water. In this case, we won’t even be able to click on the link, as there is no water to water the plant with. This is it. Thus, we have studied the whole code. It probably is the longest code so far in our course with almost 200 lines. We might have even longer codes in the future, but we haven’t written such
long sketches yet. Now let’s look how our watering system works.