420 Magazine Background

Arduinos in the grow room: My project


Well-Known Member
Switches are identical? I have push-buttons that look identical... except one is normally open and the other is normally closed. I had a similar issue and ended up marking one with a sharpie :) .

Also, ensure you're not re-purposing pinmode on the fly (admittedly does not fit you one-out-of-three situation):

Arduino - DigitalPins

Both buttons are Normally Open...
Module 1 detects the closed button on the pin as HIGH
Module 2 detects the closed button on the pin as LOW
Module 3 detects the closed button on the pin as HIGH

WAIT! I think I found it...

Module 1 and Module 3 both have a DHT-22 Digital Sensor on D9. Shouldn't matter, but just for the heck of it, I disabled that sensor on Module 3, and it started detecting a button press when there wasn't one! In other words, it's now behaving like Module 2.

I guess it's time to comb the code to see if I inadvertently set pin 8 rather than 9 somewhere, doesn't make sense, I never use numbers, only variables/constants.
Last edited:


Well-Known Member
Let me just randomly think out loud here...

If D8 is set to INPUT_PULLUP, then wouldn't that keep a floating pin (not connected or button not pressed) HIGH? PULL UP?
My understanding now is that it's a resistor between the pin and 5v to hold it HIGH while not connected...
My understanding at the tie I coded this was "Cut and Paste" from a sample somewhere... In other words, no idea what it did, but it was in the code I used to learn...

Next I wired my button so it shorted D8 to GND. This will drive the pin LOW when the button is pressed...

So, on Module 2 (without the DHT22 configured):
Normally (button not pressed) it will see the pin as HIGH because of the input_pullup
When button is pressed, pin goes LOW (short to ground)

This is confirmed, because I had to modify the code to look for LOW to trigger the scan. (button pressed)

Module 1 and 3, both have the DHT22 on pin D9, coincidentally right next to pin D8, and they BOTH behave different than Module 2, but the same as each other.

My thinking up till now was that Module 1 and 3 were correct, and Module 2 had the problem, since it was the oddball... Turns out it was the correct one, the other two are wrong somehow...

Ok, so what's wrong with 1 and 3? It definitely has to do with the DHT22 setup, because if I disable that senor on Module 3 (database setting) then Module 3 will work correctly. I did a quick code review and I didn't accidentally write to the wrong pin anywhere...

While I still don't know the specific reason (yet!) I at least know what's causing it.

Will report what I find...

more coffee...
Last edited:


Well-Known Member
Um, ok, I'm confused...

Module 2, we determined, is working correctly... I modified the code to look for LOW to signal a button press, because that's the proper behaviour.

I inspected Module 3, and found the button I used there, I actually made a little button Breakout Board, it has 2 buttons, and uses voltage dividers, making these analog buttons... They don't short the pin to ground, they would actually be applying positive voltage, causing the pin to read HIGH. The voltage divider resistor would be pulling signal (Pin) to Ground, for a LOW while the button is not pressed... Thats why on Module 3, HIGH signalled a button press, because of the button itself... Interesting :)

So, I replaced the button with a plain old button that shorts the pin to ground, and Module 3 now works as it should, with, or without the DHT22 set up....

So now, what's up with Module 1, which is still not behaving as expected... back with answers as they become available... lol


Well-Known Member
DHT22 Sensor has nothing to do with it... Coincidence that it was on the two suspicious modules, and I'm not sure why the one module changed behaviour when I disabled the sensor, but I must have done something else I didn't realize...

Module 1 still won't work properly. It reports LOW until you press the button, then HIGH. I disabled the DHT22 and no change ... so far, that's all I got, rule out the main suspect! :(


Well-Known Member
Much like Capt. Kirk, and the Kobayashi Maru, I hate losing :cool:

if (((digitalRead(scanButtonPin) == LOW) && ((moduleCfg.moduleId == 2) || (moduleCfg.moduleId == 3)))
|| ( (digitalRead(scanButtonPin) == HIGH) && (moduleCfg.moduleId == 1) ))

Now, don't get me wrong, I know better... The fact that it is not behaving as expected is a glaring warning that something is wrong, there IS a bug, somewhere... It's easy to code around issues, but unless you are 100% absolutely positive you understand WHY its not working, then you are just putting a coat of paint on it. You need to find out what is causing the problem, and see if it's causing other problems you aren't even aware of...

on the other hand, I'm retired and can do whatever I like... :) I'm just doing this so I don't have to keep changing the code for each module. I'll find the cause... not done yet...


Well-Known Member
Ok, grasping at straws here...

A hardware issue on the Mega 2560 so that the internal pullup resistor is not working? That would leave the pin LOW while the button is not pressed... But, pressing the button would not drive the pin HIGH, since it simply shorts the pin to Ground, which is LOW...

Ok, so we have two things to check...
Why is the pin LOW by default?
Why does shorting the pin to Ground cause the pin to go HIGH?


Well-Known Member
Another small step...

I added some code to print the value of the pin to the serial port. It does this at a couple places, firstly, right at the very beginning of the program before anything else (right after Serial.begin)
Second on is right after setting the pinmode to input_pullup
Third is right after scanning all the sensors

Module 3, the properly working one, reads the pin HIGH in all three spots

Module 1 reads LOW, HIGH, LOW
So before the code even does anything, they are already different.... one is LOW, one is HIGH
Then the pinmode executes, and now the pin is HIGH
Then something happens to change the pin back to LOW by the time it finishes scanning and saving.

This is where I am now, narrow the search, and keep going...


Well-Known Member
Narrowed it down to the processing of ONE SPECIFIC SENSOR... #57

It's a diy soil moisture sensor, just like the others, nothing special... but somehow, THIS specific one causes the logic to be reversed on a different pin? I can't even begin to guess how...

I'm gonna call it a night and get some sleep...


Well-Known Member
Couldn't sleep, just as well, I found the problem...

Buried way down in there where the Analog Sensors are read....

// Set the analog pin for this probe to INPUT mode
pinMode(sensorCfg[sensorIndex].analogPin, INPUT);

to set the mode for DIGITAL pin D8 (our button pin),with pullup, you would say:

to set the Analog Pin 8 for Input, you would say:

In my case sensorCfg[sensorIndex].analogPin was an INT which was assigned the value 8, which works perfectly fine when you read it, as both these are the same:


So, I was resetting D8 to INPUT without pullup, which meant it stayed LOW while the button was not pressed... I still don't understand how shorting D8 to ground would take the pin HIGH though, perhaps my curiosity will get the better of me and I''l go look it up some time... :)

Wow, I didn't notice this when I was going over the code looking for this exact issue, setting the wrong pin. but I was looking for the digitalPin variable, not the analogPin one. The reason I found this actual error was when I couldn't find ANY reason for this behavior, I looked closer at how this sensor was configured, since there are others of the same kind in use without issues. I noticed this one was on Analog Pin 8 - that couldn't be a coincidence... Took me about 2 minutes to find it then....

So yes, a bug, a coding bug, one that's been there since I read my first sensor...

For now, I've commented out that line, since an analog Pin is INPUT by default...

I also removed those silly conditions on the button check, and all 3 modules now report a press on pin being LOW, the way they should...

I may still not understand this 100% so if you see more mistakes, please let me know!


Well-Known Member
Interesting, I suppose I could have written a novel instead!

Grow By Wire (So Far, not including libraries!)

Lines - Code
3,275 - MegaModule.ino
2,251 - megaMySqlEsp8266.ino
5,031 - esp8266_WebServer.ino
1,179 - esp8266_MaintenanceServer.ino
   221 - I2C_RelayController.ino
   167 - I2C_Node.ino
    92 - I2C_WaterDepth.ino
    81 - I2C_Module_EEPROM_Write_ID.ino
12,297 Total Lines of Code
Last edited:


Well-Known Member
Remember I said that without actually finding the bug, you have no idea what else it effects? Well, now that I found this one, it does explain an issue I've noticed, only on Module 1. Occasionally when I look in on it, the RGB LED is not on... It is supposed to always show either green or red just to say things are ok or not, and also the blue LED should flash when data is sent between the Mega and ESP. So I only noticed it on Module 1 because Module 2 only has a couple sensors on it right now, and apparently not in the same pin numbers as the LEDs

const int                        ledPinRed = 10;                         // Digital Pin for RED LED anode
const int                        ledPinGreen = 11;                       // Digital Pin for GREEN LED anode
const int                        ledPinBlue = 12;                        // Digital Pin for BLUE LED anode
There were Analog Sensors on pins A10, A11, and A12, so when they were being read, the system was changing the pinmode from OUTPUT to INPUT, and obviously, they won't light up on INPUT Pins...

This same bug could cause my Serial Output to stop working... sound familiar? When I was chasing i2c bugs, I had that happen a few times.... Basically if a sensor is on A1, then Pin 1 (Tx) will be set to INPUT, so it won't be able to transmit any more... Not sure if that happened, but it's possible...

So whats the difference between Pin 8 and Pin A8 anyways?
Well, pin 8 is pin 8... Digital Pin 8.
On the Mega, there are 54 Digital Pins, 0-53, and 16 Analog Pins, A0-A15

The Digital Pin numbers are just that, numbers, I store them as Integers. (Byte would save space)
The Analog numbers, A8 can't be stored as an Integer, but the Arduino Core makes a Constant available, A8, and a DEFINE PIN_A8, and it knows, based on the board you selected, what the ACTUAL pin number is...

In my case, on the Mega, A8 = (53+9) = 62

If I want to put the line of code back in, I'd have to do this conversion myself. It appears I don't need it there anyhow, so I'll leave it commented out, and eventually remove it from the code.


Well-Known Member
You might wonder, based on my methodologies I've described here...

How the heck did that guy work as a Senior Software Engineer?

Well, it's a long story, but the short version is, computers started as a hobby back with the Commodore PET (1981?) I have no education past grade 12, no training with computers, just a passion. I'm not one for following a tutorial from a-z, so for the most part, everything I know comes from actual hands on experience, often spending hours on seemingly meaningless tasks... Because of this, I had a much deeper understanding of how things actually worked, even to the point I was coding in assembler on my first 8088.

My first job as a programmer came at a small company maybe 8 people total, 3 of us programmers, 2 junior plus one co-owner. That co-owner became my mentor for many years, and knew he could assign me a task, and it would get done, period... I'd sleep under my desk if I had to to stay until I came up with a solution... He made sure that everyone in the company knew that if it wasn't for us programmers, they wouldn't have jobs :)

My next job, I worked at home writing shareware for about 7 years. This was the birth of BBS's, putting a modem on your PC. I managed to make a living, and became personal friends with some of the biggest BBS authors of the time.

Along came the internet... I had an account, but back then you had to pay by the minute for connectivity... Obviously I would go broke, so I offered to help with Support in exchange for an account. Well, they ended up hiring me part time, then full time, then I became the support manager. I was enjoying the break from programming but was buddies with the programmer there, and saw what he was doing with the billing system.

In the mean time, a friend had started an Internet company and was having nightmares figuring out how to bill people for it, and a new company had just bought out the company I was working at. I handed in my resignation and started the next day with my friend. I spent about 2 years writing a billing system in perl on some unix system.

From there, I was lured away by a job offer from my old mentor, they had sold the company, made millions, and now started a new company, would I come work for them? Sure, things are slow here, the billing system is done...

Funny thing is, after a year or so, this new company merged back into his old company, and we ended up back in their offices, in a much larger environment. Finally he left, and I was left in charge of a huge project we were working on. I asked to have a solutions architect come in and do an architectural review of what we had, because frankly, I wasn't 100% sure what we were doing, not having had any formal training...

I became friends with the architect doing the review, we worked together for a month or so... When he was done, his report was absolutely positive, and then he offered me a job. I was already bored where I was and everybody knew it.

I went to work for him at his small consulting company, was there the rest of my career. I was his most senior engineer, and was generally in charge of the technical aspects of the other programmers (ie, not HR etc) such as scheduling, managing projects... I worked there until my mind was so addled with meds from the doctors that I had a breakdown, and ended up in a real mess for nearly 5 years. This project is the first worthwhile thing I've done in that time.

So, that was my career... I only ever applied for one job, that was the very first one, after that, jobs were always waiting, I was so lucky. I was able to pick and choose, and always chose the small shop, even solo... I liked working WITH people, not managing them. I've always been able to just up and leave one job if I wasn't happy. Unfortunately, this gave me a bit of a reputation at one company (the one I worked for twice) where my manager actually called me a "prima donna" LOL. I guess I was...

Ok, back to work, where was I...


Well-Known Member
It's clear I need to make another small change. Rather than pass only ONE value to Blynk per sensor, I want to be able to pass up to 3. I designed the system to allow up to 3 "probes" per "sensor" as this was required for the DHT-22 Temp/Humidity/HeatIndex sensor. Internally, the system stores 3 raw sensor readings, lus 3 calculated values.

A raw reading is just that, say a soil moisture sensor reading, say 765. That is 765 out of a possible 1023, so the Calculated value becomes 75 (for 75%) The dual soil moisture sensor would also have a raw2 and calc2 value.

When I added Blynk support, I allowed you to pick a sensor, and on that sensor, pick a value (Raw 1-3 or Calc 1-3) and a Blynk Virtual Pin to assign that value to. There is no option for more than one value.

Right now, we store it like so:
sensorId - INTEGER - identifies the Sensor
blynkSendValue - INTEGER - 1-6 (Raw 1-3, Calc 4-6) Which Value are we sending to Blynk
blynkVirtualPin - INTEGER - Which Blynk Virtual Pin are we assigning it to
blynkSendFreqInSeconds - INTEGER - How often do we scan this sensor and send to Blynk (not to db)

I'm going to make a change so that for each sensor you can pick 3 values to assign Blynk Virtual Pins, like so:

sensorId - INTEGER - identifies the Sensor
blynkSendValue1 - INTEGER - 1-6 (Raw 1-3, Calc 4-6) Which Value are we sending to Blynk
blynkVirtualPin1 - INTEGER - Which Blynk Virtual Pin are we assigning it to
blynkSendValue2 - INTEGER - 1-6 (Raw 1-3, Calc 4-6) Which Value are we sending to Blynk
blynkVirtualPin2 - INTEGER - Which Blynk Virtual Pin are we assigning it to
blynkSendValue3 - INTEGER - 1-6 (Raw 1-3, Calc 4-6) Which Value are we sending to Blynk
blynkVirtualPin3 - INTEGER - Which Blynk Virtual Pin are we assigning it to
blynkSendFreqInSeconds - INTEGER - How often do we scan this sensor and send to Blynk (not to db)

The reason for doing it this way is I can assign the same value (say Calc1, 75% in above example) to two or three Virtual Pins, meaning the same value can be displayed in multiple widgets, thus improving on Blynk itself :)

This will also allow me to properly graph a DHT-22 to show Temp/Humidity/Heat-Index all from one sensor.


Active Member
Are you talking about checking for SERVER connectivity, or for APP connectivity?
From that standpoint, APP connectivity. Your ATMega2560's are more than enough to handle the chatter, and it's a personal preference thing.

I just skip sending information intended solely for the client application when it's not even connected. Consider a global volatile bool that you lock and set according to the BLYNK_APP_CONNECTED() and BLYNK_APP_DISCONNECTED() events (oh, and don't forget to update your project settings if you do). Here's an example.


Well-Known Member
From that standpoint, APP connectivity. Your ATMega2560's are more than enough to handle the chatter, and it's a personal preference thing.

I just skip sending information intended solely for the client application when it's not even connected. Consider a global volatile bool that you lock and set according to the BLYNK_APP_CONNECTED() and BLYNK_APP_DISCONNECTED() events (oh, and don't forget to update your project settings if you do). Here's an example.
Just curious how reliable this would be, if it missed an event for some reason, and you never start sending data to your app, you'd be banging your phone on the table wondering why it wasn't getting updates, no? I do suppose it is well tested though, I haven't run across any bugs in the app so far. (Server admin is another story!)
Top Bottom