Show Posts
Pages: [1]
1  Topics / Home Automation and Networked Objects / Re: My 1st Home Automation system on: February 07, 2013, 10:52:51 pm
I'd love to hear how you did it - as someone who can build web apps fairly easily, the phone app process has always been a little daunting to me. If there's an easy transition available  you will have made my day/week smiley
2  Using Arduino / Programming Questions / Re: Issues with atoi conversion on: January 26, 2013, 06:36:15 pm
Thanks for the replies, everyone - I pulled an all-nighter and found that payload wasn't null-temrinated, just like PeterH said. I can't change the way it's sent (as it's coming from a third party program (MQTT)) but I converted it to a String then sorted it out from there.

Sorry for omitting the entirety of my code - I had managed to narrow it down to the code that I posted (when removing the atoi line the value didn't change every second time) but yes, I should have put it all in. For those still interested, here it is below:

Code:
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

#define datapin 2
#define clockpin 3
#define latchpin 4
int current = 0; // 00000000
const int relayValues[]={
  1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int relayCheck[] = {
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int changeVal = 0;
//char OnOrOff[] = {"off","on"};
//char DataResult[100]="Publishing data - relay "; //24
String OnOrOff;
String DataMash;
String DataResult;
byte mac[] = { 
  0xDE, 0xC0, 0xDE, 0xC0, 0xFF, 0xEE };
byte mqttserver[] = {
  192, 168, 2, 7 };
byte ip[] = {
  192, 168, 2, 101 };

//char DataMash[30]="                             ";

EthernetClient ethClient;
PubSubClient clientr(mqttserver, 1883, callback);

/////////////////// calculateRelayVal ///////////////////
int calculateRelayVal(int newVal) {

  // if newVal==0 then return value as 11111111
  // newVal has relay we need to toggle
  // referenced in relayCheck as newVal-1
  int intRelayToWorkWith = relayValues[(newVal-1)];

  if(relayCheck[(newVal-1)]==0) {
    // relay is currently off, turn on
    changeVal = current | intRelayToWorkWith;
    relayCheck[(newVal-1)]=1;
  }
  else {
    // relay is currently on, turn off
    changeVal = current ^ intRelayToWorkWith;
    relayCheck[(newVal-1)]=0;
  }

  current = changeVal;
  return current;
}

/////////////////// doWork ///////////////////
void doWork(int val) {

  // as relays need a '0' to turn on and a '1' to turn off, need to NOT this value
  unsigned int realVal = ~val;

  uint8_t rVlow = realVal & 0xff;
  uint8_t rVhigh = (realVal >> 8);

  digitalWrite(latchpin,LOW);
  shiftOut(datapin,clockpin,MSBFIRST,rVhigh);
  shiftOut(datapin,clockpin,MSBFIRST,rVlow);
  digitalWrite(latchpin,HIGH);

}

/////////////////// callback ///////////////////
static void callback(char* topic, byte* payload, unsigned int length) {
  char PublishData[24];
  char tina[4];
  String tp = (char*)payload;
  (tp.substring(0,length)).toCharArray(tina,4);
  unsigned int readVar = (unsigned int)atoi(tina);

  if(readVar<0 || (readVar>16 && readVar!=999)) {
    // if input is outside of specification (greater than 16 and not 999 (status check) or less than zero then make -1
    // -1 is used in the switch below to indicate invalid input
    readVar=-1;
  }
  if(readVar==999){
    String strGetStatus="S:";
    for(int i=0;i<16;i++){
      strGetStatus+=relayCheck[i];
    }
    strGetStatus.toCharArray(PublishData,100);
    //    clientr.publish("RelayControlReport",PublishData);
    clientr.publish("WebControl",PublishData);
  }
  else {
    if(readVar>=0 && readVar<=16) {
      int registerValue=0;
      if(readVar > 0) {
        registerValue = calculateRelayVal(readVar);
      }
      else {
        current=0;
        for(int i=0;i<16;i++){
          relayCheck[i]=0;
        }
      }
      doWork(registerValue);

      if(relayCheck[(readVar-1)]==1){
        OnOrOff=" on";
      }
      else {
        OnOrOff=" off";
      }

      if(readVar!=0){
        DataMash="Relay: ";
        DataResult = DataMash + readVar + OnOrOff;
        DataResult.toCharArray(PublishData,100);
      }
      else {
        DataResult="All relays off";
        DataResult.toCharArray(PublishData,100);
      }
      clientr.publish("RelayControlReport",PublishData);
    }
  }
}

/////////////////// setup ///////////////////
void setup()
{
  pinMode(datapin,OUTPUT);
  pinMode(clockpin,OUTPUT);
  pinMode(latchpin,OUTPUT);

  digitalWrite(latchpin,LOW);
  shiftOut(datapin,clockpin,MSBFIRST,-1);
  shiftOut(datapin,clockpin,MSBFIRST,-1);
  digitalWrite(latchpin,HIGH);

  delay(500);
  Serial.begin(9600);
  Serial.println(F("Scouris - MQTT Control, booting up."));
  Serial.print(F("Eth start .."));
  Ethernet.begin(mac,ip);

  // below is for when running with DHCP
  Serial.print(F("up, IP: "));
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(F("."));
  }
  Serial.println("");

  if(clientr.connect("arduinoClient")) {
    clientr.publish("checkInTopic","Relay Controller Online");
    clientr.publish("RelayControlReport","Relay Controller Online");
    clientr.subscribe("RelayControl");
  }
  doWork(0);
  //  delay(500);
}

/////////////////// loop ///////////////////
void loop()
{
  clientr.loop();
}
3  Using Arduino / Programming Questions / Issues with atoi conversion on: January 26, 2013, 07:09:54 am
As part of my MQTT project, I send 999 for a status report. However, when I send it the second time, the value gets changed to 0. I have narrowed the causing code to this snippet:
Code:
static void callback(char* topic, byte* payload, unsigned int length) {
  char PublishData[100];
Serial.print(F("Payload: "));
Serial.write(payload,length); // shows 999 both times
Serial.print(F(" - "));

  int readVar = (unsigned int)atoi((char*) payload);

Serial.println(readVar);      // first time shows 999, second time shows 0
and here is the output from the Serial log:
Code:
Payload: 999 - 999
Payload: 999 - 0
Payload: 999 - 999
Payload: 999 - 0
Payload: 999 - 999
Payload: 999 - 0
Payload: 999 - 999
Payload: 999 - 0
I need the byte* payload to get converted to an int but it appears the atoi line is wrong, somehow. What have I done wrong?
4  Using Arduino / Programming Questions / Re: Device keeps resetting randomly on: January 24, 2013, 05:19:48 pm
Thanks guys.
As a quick edit before I left for work this morning, I removed all un-necessary Serial.print()'s and the ones that were left I changed them to be Serial.print(F()) as AWOL described. The program seems to run fairly well now - frantic mashing of the keyboard to send commands to it fails to make it fall over.

Having said that, this evening I'm going to take your advice, Nick, and get rid of the Strings. One thing that I was trying to work out on the drive to work this morning was this section:

Code:
String strGetStatus="Status check: ";
    for(int i=0;i<16;i++){
      strGetStatus+=relayCheck[i];
    }
    strGetStatus.toCharArray(PublishData,100);
If I were to get rid of the String strGetStatus and instead make it a char*, would something like this be the way to go:

Code:
char* chrGetStatus[35]="Status check: ";
for(int i=0;i<16;i++){
chrGetStatus[(15+i)]=relayCheck[i];
}

Actually, writing that out it looks to me like double handling. the relayCheck is an int* - how would I convert this to a char array so I can publish it's value? At present, using the String method, I get a string of 0's or 1's that indicate which relay is on or off, and the web monitor currently looks at this, so I'd like it to come out the same.
5  Using Arduino / Programming Questions / Device keeps resetting randomly on: January 24, 2013, 05:19:47 am
I've seen a lot of home automation projects out there that use the Arduino and one that I particularily liked uses MQTT to get/send messages over Ethernet as a publishing system. I've come up with the following code for my project - at this point it controls a 16-relay board.
The device registers with an MQTT server (running on a rPi) and listens for commands. These I send to the MQTT server which pushs them out to the Arduino. I send numbers 1-16 to essentially switch the state of the relay (on if off and vice-versa). I can also send '999' to get a status line which shows which relays are on and which are off. If I send a number larger than 16 but less than 999 then it doesn't do anything, returns 'Invalid input'.
When it works, it works fine. Sometimes it loses commands that are sent to it (and I can confirm it receives by the mountain of serial debugging code I've put in, as you can see). And at other times (especially if I send commands to it quickly) it will just reset all on it's own.
I have tested this with no additional boards on the Arduino (except for ethernet) and across two different Arduino's and the problem still exists, leading me to believe it's my code.
I'm open to any suggestions or criticisms - please let me know what I'm doing wrong!
Pastebin link to code here http://pastebin.com/JX7Hgg5L in case it's too large for below.

Code:
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

#define datapin 2
#define clockpin 3
#define latchpin 4
int current = 0; // 00000000
const int relayValues[]={
  1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
int relayCheck[] = {
  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
int changeVal = 0;
String OnOrOff;
String DataResult;

byte mac[] = { 
  0xDE, 0xC0, 0xDE, 0xC0, 0xFF, 0xEE };
byte mqttserver[] = {
  192, 168, 2, 7 };
byte ip[] = {
  192, 168, 2, 101 };

EthernetClient ethClient;
PubSubClient clientr(mqttserver, 1883, callback);

/////////////////// calculateRelayVal ///////////////////
int calculateRelayVal(int newVal) {

  Serial.print("Starting calculateRelayVal with val of ");
  Serial.println(newVal);
  Serial.print("Current value is ");
  Serial.println(current);

  // if newVal==0 then return value as 11111111

  // newVal has relay we need to toggle
  // referenced in relayCheck as newVal-1


  int intRelayToWorkWith = relayValues[(newVal-1)];

  if(relayCheck[(newVal-1)]==0) {
    // relay is currently off, turn on
    changeVal = current | intRelayToWorkWith;
    relayCheck[(newVal-1)]=1;
  }
  else {
    // relay is currently on, turn off
    changeVal = current ^ intRelayToWorkWith;
    relayCheck[(newVal-1)]=0;
  }

  Serial.print("Finished checking values, changeVal currently ");
  Serial.println(changeVal);

  current = changeVal;
  return current;
  Serial.println("completing calculateRelayVal");
  Serial.println("");
}

/////////////////// doWork ///////////////////
void doWork(int val) {

  Serial.println("");
  Serial.print("doWork starting with val of ");
  Serial.println(val);

  // as relays need a '0' to turn on and a '1' to turn off, need to NOT this value
  unsigned int realVal = ~val;

  Serial.print("Doing NOT conversion gives result of ");
  Serial.println(realVal);

  Serial.println("Splitting into two parts for registers ...");
  uint8_t rVlow = realVal & 0xff;
  uint8_t rVhigh = (realVal >> 8);
  Serial.print("Low: ");
  Serial.println(rVlow);
  Serial.print("High: ");
  Serial.println(rVhigh);

  digitalWrite(latchpin,LOW);
  shiftOut(datapin,clockpin,MSBFIRST,rVhigh);
  shiftOut(datapin,clockpin,MSBFIRST,rVlow);
  digitalWrite(latchpin,HIGH);

  Serial.println("sent value, closing doWork");
  Serial.println("");
}

/////////////////// callback ///////////////////
static void callback(char* topic, byte* payload, unsigned int length) {
  char PublishData[100];
  Serial.print("callback with payload ");
  Serial.write(payload,(length/2)); // for some reason length is twice as long as it needs to be

  int readVar = (unsigned int)atoi((char *) payload);
  if(readVar==999) {

    Serial.println("Status check requested.");

    String strGetStatus="Status check: ";
    for(int i=0;i<16;i++){
      strGetStatus+=relayCheck[i];
    }
    strGetStatus.toCharArray(PublishData,100);
    clientr.publish("RelayControlReport", PublishData);
    clientr.publish("WebStatusCheck", PublishData);

    Serial.print("Status check sent as: ");
    Serial.println(strGetStatus);
  }
  else if(readVar>16) {
     Serial.print("Invalid input detected: ");
     Serial.write(payload,(length/2));
     clientr.publish("RelayControlReport","Invalid input");
  }
  else {
    Serial.println(readVar);
    String debugcalReV = "Calling calculateRelayVal with the payload of ";
    String debugcalReVGO = debugcalReV + readVar;
    Serial.print(debugcalReVGO);
    Serial.println(" ... ");
    int registerValue=0;
    if(readVar != 0) {
      registerValue = calculateRelayVal(readVar); 
    }
    else { // turns all relays off if received value is zero
      current=0;
      for(int i=0;i< 16;i++){
        relayCheck[i]=0;
      }
    }

    String debugregVal = "registerValue is set to ";
    String debugregValGO = debugregVal + registerValue;
    Serial.println(debugregValGO);
    Serial.println("doing work now for above value ... ");

    doWork(registerValue);

    String debugdoWork = "doWork complete for ";
    String debugdoWorkGO = debugdoWork + registerValue;
    Serial.println(debugdoWorkGO);

    if(relayCheck[(readVar-1)]==1) {
      OnOrOff = " turned on.";
    }
    else {
      OnOrOff = " turned off.";
    }
    if(readVar!=0){
      String DataMash = "Publishing data - relay ";
      DataResult = DataMash + readVar + OnOrOff;
      DataResult.toCharArray(PublishData,100);
    }
    else {
      DataResult = "All relays turned OFF";
      DataResult.toCharArray(PublishData,100);
    }
    clientr.publish("RelayControlReport", PublishData);
    Serial.println(DataResult);
  }

}

/////////////////// setup ///////////////////
void setup()
{
  pinMode(datapin,OUTPUT);
  pinMode(clockpin,OUTPUT);
  pinMode(latchpin,OUTPUT);
  digitalWrite(latchpin,LOW);
  shiftOut(datapin,clockpin,MSBFIRST,-1);
  shiftOut(datapin,clockpin,MSBFIRST,-1);
  digitalWrite(latchpin,HIGH);
  delay(500);
  Serial.begin(9600);
  Serial.println("Scouris - MQTT Control, booting up.");
  Serial.println("Initialising Ethernet ...");
  Ethernet.begin(mac,ip);

  // below is for when running with DHCP
  Serial.print("Ethernet is up with IP of ");
  for (byte thisByte = 0; thisByte < 4; thisByte++) {
    // print the value of each byte of the IP address:
    Serial.print(Ethernet.localIP()[thisByte], DEC);
    Serial.print(".");
  }

  if(clientr.connect("arduinoClient")) {
    clientr.publish("checkInTopic","Relay Controller Online");
    clientr.publish("RelayControlReport","Relay Controller Online");
    clientr.subscribe("RelayControl");
  }

  delay(500);

  Serial.println("Resetting relays to OFF ...");
  doWork(0);
  delay(1000);
  Serial.println("Setting all to on for test ...");
  doWork(-1);
  delay(1000);
  doWork(0);
  Serial.println("Continuing.");
  delay(1000);
}

/////////////////// loop ///////////////////
void loop()
{
  clientr.loop();
}
6  Using Arduino / Programming Questions / Re: Sending negative numbers to shiftOut() on: December 28, 2012, 02:55:21 pm
Thanks for the responses, greatly appreciated.
In all the examples I've seen with using shiftOut it uses numbers between 0-255 so I was concerned when I saw my debug messages dumping negative numbers.
I'll re-do my physical circuit and see if I haven't managed to hook the wrong pins up somewhere smiley

Many thanks  smiley

Edit: found out what my problem was. Total noobish mistake - in one of my editing frenzies, I removed the declarations for latchpin, clockpin and datapin as OUTPUTs. Put those in and it's all good now. Thanks again!
7  Using Arduino / Programming Questions / Sending negative numbers to shiftOut() on: December 28, 2012, 06:53:56 am
Hi all,
I'm trying to get my Arduino talking to a 16 relay board I picked up using a shift register - at this point in time I'm only working with 8 but once it's all working will move to use all 16.
I am using MQTT to receive a number relating to which relay to turn on or off. My code checks this number against a current status array and turns it on or off accordingly. I decided to have (to start with) an integer with zero value. I also have an array with my relay values as follows:
Code:
const int relayValues[]={1,2,4,8,16,32,64,128};
This way I can get the number of the relay that is being flipped, subtract 1 from it and get it's index value from this array. I then check if it's currently on or off - if it's on I XOR it with the current status, if it's off I OR it.
For example, if I received a value of 3, it would return 4 from this array. If no other relays are on, it would OR with the current value (which is an int that begins as 0) and output the new number (in this case 4).
I then send this number to my shift register after NOT-ing it, as my relay board uses a 1 to turn the relay off and 0 to turn it on. This then makes the value (in the example) -5.
My problem is this: my shiftOut command then looks like this:
Code:
shiftOut(datapin,clockpin,MSBFIRST,-5)
but nothing gets received at the other side of the shift register.
I'm confused why I'm getting -5 instead of 251 and if this would be causing my shift register to sit there with a dumb look on its face.
(the number in binary after NOTing is 11111011)

Full code below, criticism welcomed as I'm flying by the seat of my pants here.
Thanks smiley-grin

Code:
#include <SPI.h>
#include <Ethernet.h>
#include <PubSubClient.h>

#define datapin 2
#define clockpin 3
#define latchpin 4
int current = 0; // 00000000

const int relayValues[]={1,2,4,8,16,32,64,128};
int relayCheck[] = {0,0,0,0,0,0,0,0};
int changeVal = 0;
int chkOnOff[]={0,1};
String OnOrOff;

byte mac[] = { 
  0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x02 };
byte mqttserver[] = { 192, 168, 2, 7 };

EthernetClient ethClient;
PubSubClient clientr(mqttserver, 1883, callback);


int calculateRelayVal(int newVal) {
 
    Serial.print("Starting calculateRelayVal with val of ");
    Serial.println(newVal);
    Serial.print("Current value is ");
    Serial.println(current);
 
// newVal has relay we need to toggle
// referenced in relayCheck as newVal-1

int intRelayToWorkWith = relayValues[(newVal-1)];

if(relayCheck[(newVal-1)]==0) {
// relay is currently off, turn on
changeVal = current | intRelayToWorkWith;
relayCheck[(newVal-1)]=1;
} else {
// relay is currently on, turn off
changeVal = current ^ intRelayToWorkWith;
relayCheck[(newVal-1)]=0;
}

Serial.print("Finished checking values, changeVal currently ");
Serial.println(changeVal);

current = changeVal;
return current;
Serial.println("completing calculateRelayVal");
Serial.println("");
}
void doWork(int val) {
 
    Serial.println("");
    Serial.print("doWork starting with val of ");
    Serial.println(val);
 
// as relays need a '0' to turn on and a '1' to turn off, need to NOT this value
       
int realVal = ~val;

  Serial.print("Doing NOT conversion gives result of ");
  Serial.println(realVal);

digitalWrite(latchpin,LOW);
shiftOut(datapin,clockpin,MSBFIRST,realVal);
digitalWrite(latchpin,HIGH);

Serial.println("sent value, closing doWork");
Serial.println("");
}



static void callback(char* topic, byte* payload, unsigned int length) {
 
  Serial.print("callback with payload ");
  length=length/2;
  Serial.write(payload,length);
 
  int readVar = (unsigned int)atoi((char *) payload);
 
  Serial.println(readVar);
  String debugcalReV = "Calling calculateRelayVal with the payload of ";
  String debugcalReVGO = debugcalReV + readVar;
  Serial.print(debugcalReVGO);
  Serial.println(" ... ");
 
  int registerValue = calculateRelayVal(readVar); 
 
  String debugregVal = "registerValue is set to ";
  String debugregValGO = debugregVal + registerValue;
  Serial.println(debugregValGO);
  Serial.println("doing work now for above value ... ");
 
  doWork(registerValue);
 
  String debugdoWork = "doWork complete for ";
  String debugdoWorkGO = debugdoWork + registerValue;
  Serial.println(debugdoWorkGO);
 
  if(relayCheck[(readVar-1)]==1) {
    OnOrOff = " turned on.";
  } else {
    OnOrOff = " turned off.";
  }
  String DataMash = "Publishing data - relay ";
  String DataResult = DataMash + readVar + OnOrOff;
  Serial.println(DataResult);
  char PublishData[100];
  DataResult.toCharArray(PublishData,100);

  clientr.publish("RelayControlReport", PublishData);
 
}




void setup()
{
  Serial.begin(9600);
 
  if (Ethernet.begin(mac) == 0) {
    Serial.println("Failed to configure Ethernet using DHCP");
    // no point in carrying on, so do nothing forevermore:
    for(;;)
      ;
  }
  if(clientr.connect("arduinoClient")) {
     clientr.publish("checkInTopic","Relay Controller Online");
     clientr.publish("RelayControlReport","Relay Controller Online");
    clientr.subscribe("RelayControl");
  }
 
delay(500);
Serial.println("Scouris - MQTT Control, booting up.");
Serial.println("Resetting relays to OFF ...");
doWork(0);
Serial.println("Continuing.");
  delay(1000);
}


void loop()
{
  clientr.loop();
}
Pages: [1]