Help appending code to the Tinker Firmware for Photon

I am trying to add a simple switch to the Tinker FW but, I am having trouble with its result and I am hoping someone can point me in the right direction!

//This code works on its own (Photon)
//The 3.3V pin is connected to D0 and when I disconnect the wire the Spark.publish works fine.


void setup() {
pinMode(D0, INPUT);
}

void loop() {
if (digitalRead(D0) == LOW) {
Spark.publish("door_opened", "HOME", 30, PRIVATE);
delay(3000);
while (digitalRead(D0) == LOW); // hang on until switch closes
}
}

When I add this to the Tinker FW, and disconnect the wire from D0, nothing gets published! Then I use the Tinker app and set the D0 to digitalRead. After few seconds I receive the Spark.publish but, then the Photon is no longer accessible and I have to disconnect it from power!

void setup()
{
Spark.function("digitalread", tinkerDigitalRead);
Spark.function("digitalwrite", tinkerDigitalWrite);
Spark.function("analogread", tinkerAnalogRead);
Spark.function("analogwrite", tinkerAnalogWrite);

//PUT YOUR SETUP CODE HERE
pinMode(D0, INPUT);

}

void loop()
{
//PUT YOUR LOOP CODE HERE
if (digitalRead(D0) == LOW) {
Spark.publish("switch_opened", "TEST", 30, PRIVATE);
delay(3000);
while (digitalRead(D0) == LOW); // hang on until switch closes
}

}

What happens when you re-attach the wire again? Unless that happens, you’re in a blocking endless loop. Not sure why you’re doing it that way, but I’m pretty sure there are better ways to achieve it.
What happens if you take that while loop out?

When I connect re-connect the wire I get one Spark.publish, but no matter what I do next, nothing happens! And then the Tinker app indictor turns red, which at that point I have to disconnect the Photon from its power source and re-connect it.

When you say switch in your comment and the code…do you mean the c++ switch statement or a physical switch?

Physical switch

Can you show how everything is wired up?

It seems like you might not have a pull-up resistor so digitalRead(D0) is reading a LOW and blocked here - while (digitalRead(D0) == LOW); // hang on until switch closes resulting in the lost of :cloud: connection

You can try using pinMode(D0, INPUT_PULLUP); but do not use the tinker app to set it to digital read. It should just work without having to use the tinker app.

Hope this helps!

The connections are simple.
The Photon is connected to a 5.0V source with USB
The 3V3 pin is connected to pin D0 with a jumper wire

When i use the code outside of the Tinker FW everything works as expected. Everytime D0 gets disconneted from 3V3, several Spark.publish are generated until the two pins are connected again.

Fa possible I’m missing something but switch is a c++ term and I’m surprised it’s compiling. Switch statements are something different all together than a physical switch. Is that your entire sketch? Your being stuck in your while statement is still an issue but I think you have another one coming. Or that is the issue itself. Still learning myself but it just doesn’t look right.

What is pulling to pin low? Are you connecting D0 to GND to test?

@LukeUSMC,

there’s no switch statement if you read the code above.

Like I said, I’m learning but switch is uncommented in the second code block and that was the only difference I saw.
Nm…I see now…before setup.

@Rons Give this code a try… it sounds like you are leaving your D0 pin floating when your wire/switch from 3V3 to D0 is removed. It needs to instead be pulled low, and you can do that by setting the D0 pin to INPUT_PULLDOWN. I have not omitted D0 from Tinker’s control though, so if you want to set it as an INPUT or OUTPUT or PWM you still can. That might be bad for your situation though, so unless you give us some more insight into how this is to be used it will be hard to help you with the code.

/**
 ******************************************************************************
 * @file    application.cpp
 * @authors Satish Nair, Zachary Crockett, Mohit Bhoite and Brett Walach
 * @version V1.0.1
 * @date    27-February-2015
 * @brief   Tinker application
 ******************************************************************************
  Copyright (c) 2013-2015 Particle Industries, Inc.  All rights reserved.

  This program is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation, either
  version 3 of the License, or (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this program; if not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "application.h"

/* Function prototypes -------------------------------------------------------*/
int tinkerDigitalRead(String pin);
int tinkerDigitalWrite(String command);
int tinkerAnalogRead(String pin);
int tinkerAnalogWrite(String command);

bool TRIPPED = false;

SYSTEM_MODE(AUTOMATIC);

/* This function is called once at start up ----------------------------------*/
void setup()
{
	//Setup the Tinker application here

	//Register all the Tinker functions
	Particle.function("digitalread", tinkerDigitalRead);
    Particle.function("digitalwrite", tinkerDigitalWrite);
	Particle.function("analogread", tinkerAnalogRead);
	Particle.function("analogwrite", tinkerAnalogWrite);
    
    // Don't leave D0 floating, ensure it gets pulled low when open.
    pinMode(D0, INPUT_PULLDOWN);
}

/* This function loops forever --------------------------------------------*/
void loop()
{
	// A wire/switch is normally connected from 3V3 to D0, 
	// when removed the internal pulldown resistor will bring D0 low.
	if (digitalRead(D0) == LOW && !TRIPPED) {
        Particle.publish("door_opened", "HOME", 30, PRIVATE);
        delay(1000); // delay to ensure minimum rate limiting duration met
        TRIPPED = true;
	}
	
	// reset the tripped flag when the wire/switch is reconnected
	// to 3V3 to prevent multiple publishes.
	if (digitalRead(D0) == LOW && TRIPPED) {
	    delay(100); // delay to ensure the bouncing contacts have settled
	    TRIPPED = false;
	}
}

/*******************************************************************************
 * Function Name  : tinkerDigitalRead
 * Description    : Reads the digital value of a given pin
 * Input          : Pin
 * Output         : None.
 * Return         : Value of the pin (0 or 1) in INT type
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerDigitalRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		pinMode(pinNumber, INPUT_PULLDOWN);
		return digitalRead(pinNumber);
	}
	else if (pin.startsWith("A"))
	{
		pinMode(pinNumber+10, INPUT_PULLDOWN);
		return digitalRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerDigitalWrite
 * Description    : Sets the specified pin HIGH or LOW
 * Input          : Pin and value
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerDigitalWrite(String command)
{
	bool value = 0;
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(command.substring(3,7) == "HIGH") value = 1;
	else if(command.substring(3,6) == "LOW") value = 0;
	else return -2;

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		digitalWrite(pinNumber, value);
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		digitalWrite(pinNumber+10, value);
		return 1;
	}
	else return -3;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogRead
 * Description    : Reads the analog value of a pin
 * Input          : Pin
 * Output         : None.
 * Return         : Returns the analog value in INT type (0 to 4095)
                    Returns a negative number on failure
 *******************************************************************************/
int tinkerAnalogRead(String pin)
{
	//convert ascii to integer
	int pinNumber = pin.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	if(pin.startsWith("D"))
	{
		return -3;
	}
	else if (pin.startsWith("A"))
	{
		return analogRead(pinNumber+10);
	}
	return -2;
}

/*******************************************************************************
 * Function Name  : tinkerAnalogWrite
 * Description    : Writes an analog value (PWM) to the specified pin
 * Input          : Pin and Value (0 to 255)
 * Output         : None.
 * Return         : 1 on success and a negative number on failure
 *******************************************************************************/
int tinkerAnalogWrite(String command)
{
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
	if (pinNumber< 0 || pinNumber >7) return -1;

	String value = command.substring(3);

	if(command.startsWith("D"))
	{
		pinMode(pinNumber, OUTPUT);
		analogWrite(pinNumber, value.toInt());
		return 1;
	}
	else if(command.startsWith("A"))
	{
		pinMode(pinNumber+10, OUTPUT);
		analogWrite(pinNumber+10, value.toInt());
		return 1;
	}
	else return -2;
}

Thank you. I’ll give that a try and let you know the outcome.

All I’m trying to achieve is to create a simple test with 2 wires for receiving notifications via IFTTT when the door opens. The reason I would like to incorporate this into the Tinker FW is to utilize all the great functions you guys have put forward in the app.

As I mentioned before, the code works when it is compiled by itself. Also, I am aware that there are many other ways to achieve this.
I hope I was able to provide enough information to clear things up, but if you need more information, don’t hesitate to ask.

Just to wrap things up that others have already pointed out.

  • When you leave a pin open/floating/not connected you need to apply pull-up/pull-down resistors (e.g. with pinMode(D0, INPUT_PULLDOWN) when you want to detect LOW reliably when disconnected).
  • If you want your device to stay cloud-connected, you cannot have a blocking loop like while (digitalRead(D0) == LOW);, you need to either break out of it in less than 10sec or do it like this while (digitalRead(D0) == LOW) Particle.process();
  • When you do this as attachment to Tinker firmware you have to be aware, that Tinker FW does set the pinMode(D0, *) whenever you access D0 unless you spare out D0 in the respective Spark.function()s
2 Likes

@BDub Thank you for the modified code. I tried it and worked as I was expeting. I’ll add a 10K pull-up resistor between 3V3 and D0 too!

@Scruff Thank you for your input and I will go ahead and add the pull-up resistor.

You won’t need an external pull-resistor. You can just make use of the internal ones via INPUT_PULLUP/INPUT_PULLDOWN.

Glad to hear it’s working :wink:

Actually, if you want to use an external resistor to tie the D0 pin to a voltage potential, you should tie it from D0 to GND. As ScruffR points out, you don’t really need it though if you use the internal INPUT_PULLDOWN.

Also, you should add code that prevents the D0 pin from being set in any of the tinker functions, because you could damage the pin if your switch is shorting D0 to 3V3 and you set D0 to an OUTPUT with digitalWrite() or analogWrite() and it gets set low.

@Scruff @BDub Thanks for the recommendations. After I made the comment about the external resistor, I relized that the resistor is not required! Also, I went ahead and disabled D0 in the app.

2 Likes

Brett - Since I am new to the µCs, I want to make sure I made the right edits to the Tinker FW in order to disable the D0 digitalWrite & analogWrite!

int tinkerDigitalWrite(String command)
{
	bool value = 0;
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
        //I changed < 0 to < 1
	if (pinNumber< 1 || pinNumber >7) return -1;

int tinkerAnalogWrite(String command)
{
	//convert ascii to integer
	int pinNumber = command.charAt(1) - '0';
	//Sanity check to see if the pin numbers are within limits
        //I changed < 0 to < 1
	if (pinNumber< 1 || pinNumber >7) return -1;

Now when I select D0 digitalWrite or analogWrite, I get an error message
Device pin error
There was a problem writing to this pin

I am assuming that the D0 pin digitalWrite and analogWrite are disabled!
Please let me know if there is a better method for disabling the D0 pin.

Thanks

Looks good to me :smile: