How to make button one become an 'on/off' button on IOT buddy

Hi all, new to working with the imp, i have a question for Joel Wehr or anyone who has used IOT Buddy or similar or infact anyone that knows how to do this. I want make pin 1 to HIGH when I press button 1 and then pin 1 to LOW when I press button 1 again, so the button turns into an on/off switch basicly, how is that done? I know i can use button 2 as an off switch but I need that button for something else.

This is the very basic code I have just for pin 1, I’ve given pin 1 a 5 second timer but I really do not want that to happen, would much rather toggle between high and low from one button:

function set(value) {
if value ==1 {
hardware.pin1.write(1);
imp.sleep(5.0);
hardware.pin1.write(0);
}

I guess I would use a global to hold the state of the thing that was being switched.

state <- 0; function set(value) { if value ==1 { if (state == 0) { hardware.pin1.write(1); state = 1; } else if (state == 1) { hardware.pin1.write(0); state = 0; } } }

If you want to look at a more complex example, the code I use for the security system and garage door opener with my Pitchfork app actually hold the state of the system and can retrieve it back to the app. I keep track of state in the agent and in the device.

If you have some kind of physical button (momentary), you probably will need to de-bounce it so you don’t get multiple changes on one push.

Another way to change the value is to simply use XOR to change the state.

Start out with the global variable …
state <- 0;

Here is how XOR logic works …
XOR = “one or the other but not both”.
If it’s 0 (OFF), and you XOR it with a 1, it will be 1 (ON)
If it’s 1 (ON), and you XOR it with a 1, it will be 0 (OFF)

Here is the line for XOR …
state=value ^ state;

I actually didn’t test it, but to me it looks like it should work.

If you’re just flipping the state of a DIGITAL_OUT pin, you actually don’t need a state variable. If you do a pin.read() on a DIGITAL_OUT pin, it will return whether it’s currently being driven high or low.

From the hardware.pin.read documentation:

All non-analog uses of the pin.read() will return the actual state of the pin even if it's configured for output

This let’s you write nifty code like this:
// pin - a DIGITAL_OUT pin function togglePin(pin) { pin.write(1-pin.read()); }

ooooh…pretty! :slight_smile:

That takes me way back to assembly languages where the programmer tries to conserve every byte and every clock cycle. It’s way more fun to do it with 10 lines of code though :>

Wow thank you all for the responses, will update everyone soon.

Hi everyone, this is Musa, the guy who originally posted this discussion, had to change accounts as my old one wasn’t working for some reason. I’m waiting for our product designers to finish our prototype and solder on an April board so I haven’t been able to try the code that was given above and I won’t be able to for at least another 2 weeks. In the mean time I thought i’d attempt to write the code without our prototype and simply try it once it has arrived.

While the code given by Bearded Inventor looks great, its simply too complex for a programming novice like me. Joel Wehr’s example with a global looked a bit easier for me so I went with that route.

Before I show my example code I want to clarify a few things. The project is a DC motor soldered to a rf receiver and motor controller. The April board is connected to a 1 channel rf transmitter that can make the motor rotate clockwise or anti clockwise. (yes we can attach an April board directly to the motor controller, but we have to do it this way for reasons I can’t explain). I’m using Joel Wehr’s Iot Buddy to controll the motor from my smartphone, button one (value 1) moves the motor clockwise and pressing button one again stops the motor, button 2 (value 2) moves the motor anti clockwise and stops stops once its pressed again. Pin 1 is connected to the clockwise input of the transmitter and pin 2 the anti clockwise. And of course I got my URL by adding an “HTTP IN” from the Electric Imp Planner. Here’s the code I’ve written, please let me know if I’ve done something wrong or if it could be improved.

Class input extends InputPort
{
name = "Motor Controller"
type = "Number"
state < - 0 ;
function set(value) {
if value ==1 {
if (state == 0) {
hardware.pin1.write(1);
state = 1;
}
else if (state == 1) {
hardware.pin1.write(0);
state = 0;
}
if value ==2 {
if (state == 0) {
hardware.pin2.write(1);
state = 1;
}
else if (state == 1) {
hardware.pin2.write(0);
state = 0;
}
}
}
hardware.pin1.configure(DIGITAL_OUT);
hardware.pin1.write(0);
hardware.pin2.configure(DIGITAL_OUT);
hardware.pin2.write(0);
imp.configure(“IoT Buddy”, [input( )], [ ]);

Please let me know if there are any foreseeable faults, and be gentle I’m a complete novice at programming. Thanks in advance.

hmm, “HTTP IN” has been retired…

Now that the planner has been officially retired, I would encourage you to download and use my other app, Pitchfork to control this device (It’s free). Pitchfork sends JSON data, which is just a table of key:value pairs. For example, if you assign the value “on” to Button 1, it will pass this pair: “button1”:“on”. It is really easy to parse that out in the agent, and I have example code that you can use.

If you use this code the way it is, you don’t even have to enter a value for the buttons if you dont want to. You can just modify the each button handler in the device code. Maybe set up three buttons instead, and have a clockwise, stop, and counterclockwise button? In the code below, button 1 would turn one way, button 2, would stop it from turning either way, and button 3, would turn it the other way.

agent.on("button1", function(a) { local data = ""; if (a == "") { hardware.pin1.write(1); data = "Button 1 pressed."; } agent.send("button1", data) }); agent.on("button2", function(a) { local data = ""; if (a == "") { hardware.pin1.write(0); hardware.pin2.write(0); data = "Button 2 pressed."; } agent.send("button2", data) }); agent.on("button3", function(a) { local data = ""; if (a == "") { hardware.pin2.write(1); data = "Button 3 pressed."; } agent.send("button3", data) });

Let me know if you have any questions.

@jwehr
any plans to translate Pitchfork to Android?

As much as I would like to, I’d have to learn how to use Eclipse, and program in Java.I realize that there are more android IoT users, but I’m going to stick with iOS for now, as I have invested a decent amount of time into it. (And I just got an iPhone 5S) :slight_smile:

ahhhh Crud! had no idea planner had retired. Thanks Joel and yes looks like I will have to use pitchfork and thanks for the code, I’m guessing that’s the agent code, any chance you can show me what the device code would be? Sorry to be a pain but I honestly have no idea how to use agents or JSON data.

Oh and yes the 3 button options sounds better.

Full code for agent and device are on the GitHub page that I posted. The code that posted above is just a suggestion based on what you are doing.

Can your motor controller PWM the motor, or is it just on and off? I’m trying to set up the Pitchfork control panel to work well with bots, drones ect.

OK I’ll have a look, no the controller doesn’t use PWM just a simple on and off with transistors I believe. The hardware guys told me that the programme has to make pins 1 and 2 HIGH and LOW when requested by the app.

@Joel, I’m looking the agent code on Github and I was confused with the first line:

const API_KEY = “”; //Make up a secure code, and enter it here and in the app

First is that neccesary? Second if it is how do I enter it in the Pitchfork app?

It isn’t necessary, it’s just an extra bit of security. You set the API-Key in the Control Panel settings page, with the rest of the settings. You can leave them both blank, or take the line out of the agent code that checks for it, or just enter a simple key in both. It is practically zero effort for a whole extra layer of security.

Ahh ok makes sense and yes I can see it in the App now, thanks Joel

@Joel I gave it a go with the agent code, can you tell me what needs to be changed? I used “0000” as the Api for this example

const API_KEY = “0000”;
http.onrequest(function (req, resp) {
try {
local data = http.jsondecode(req.body);
server.log("Received: " + req.body);
if (“0000” in req.headers && req.headers[“0000”] == API_KEY) {
server.log(req.headers[“0000”]);
if (“button1” in data) {
device.send(“button1”, data.button1);
device.on(“button1”, function(d) {
local json = “{ “status” : { “button1” : “” + d + “” }}”;
resp.send(200,json);
});
}
else if (“button2” in data) {
device.send(“button2”, data.button2);
device.on(“button2”, function(d) {
local json = “{ “status” : { “button2” : “” + d + “” }}”;
resp.send(200,json);
});
}
else if (“button3” in data) {
device.send(“button3”, data.button3);
device.on(“button3”, function(d) {
local json = “{ “status” : { “button3” : “” + d + “” }}”;
resp.send(200,json);
});
}
}
else {
local json = “{ “status” : { “auth” : “no” }}”;
resp.send(401, json);
}
}
catch (ex) {
resp.send(500, "Internal Server Error: " + ex);
}
});

When you paste code into the forum, click the “C” and it will insert code tags. This formats your code nicely.

You don’t need to change this line, just leave it as is:

if ("api-key" in req.headers && req.headers["api-key"] == API_KEY) {

Just put your API key in the const API_KEY.

This is what that line is actually saying:

if the key, “api-key” exists in the request headers, and the value for the key “api-key” in the request headers is equal to the constant API_KEY…