[SOLVED] My tweeting sketch is dying

I have a sketch that intercepts rf signals in my house and then tweets the result. Source code is here GitHub - pauly/rf-butler: Lightwaverf home automation 433mhz control for Arduino, without relying on the wifi link hardware and I'll paste it below too. At some stage in its development I've introduced an error whereby the sketch just stops, nothing more output on the serial monitor (and no more tweets) after the first one. I think perhaps I'm writing over the end of a string or something similar, but possibly there is an issue with how I'm posting my requests. Any help gratefully received.

/**
 * Uses https://github.com/roberttidey/LightwaveRF
 * and maybe bits of https://github.com/lawrie/LightwaveRF
 * 
 * Arduino home automation experiments. Hardware:
 *  Arduino http://amzn.to/UCKWsq
 *  Ethernet shield http://amzn.to/1akfeTY
 *  LightwaveRF kit: http://amzn.to/RkukDo and http://amzn.to/V7yPPK
 *  RF transmitter and receiver http://bit.ly/HhltyI
 *  Air quality meter from coolcomponents.co.uk
 * 
 * @author PC <paul.clarke+paulclarke@holidayextras.com>
 * @date    Wed 23 Oct 2013 20:57:15 BST
 */

#include <LwRx.h>
#include <SPI.h>
#include <Ethernet.h>
// put your twitter.com credentials in Tweet.h - copy Tweet.h.sample - optional and experimental!
#include "Tweet.h"
#define TIME_BETWEEN_NAGS 60

EthernetClient client; // to make outbound connections
byte mac[] = { 0x64, 0xA7, 0x69, 0x0D, 0x21, 0x21 }; // mac address of this arduino
byte len = 10;
byte lastCommand[10];

int airQualityPin = A0; // input pin for the air quality
int smell = 0;  // air quality value
long transmitTimeout = 0;
unsigned long lastAlerted = 0;

void setup ( ) {
  Ethernet.begin( mac ); // dhcp
  delay( 1000 );
  lwrx_setup( 2 );  // set up with rx into pin 2
  Serial.begin( 9600 );
  Serial.println( "Set up completed" );
}

void loop ( ) {
  if ( lwrx_message( )) {
    byte msg[ len ];
    lwrx_getmessage( msg, &len );
    log( msg, len );
    Serial.println( "logged, back in loop( )" );
  }
  sniff( );
  Serial.println( "sniffed, back in loop( )" );
  delay( 500 );
}

/**
 * Check the air quality
 */
void sniff ( ) {
  smell = analogRead( airQualityPin );
  if ( smell > 400 ) {
    Serial.print( "air: " );
    Serial.println( smell );
    if (( lastAlerted == 0 ) || (( millis( ) - lastAlerted ) / 1000 > TIME_BETWEEN_NAGS )) {
      char data[128];
      data[0] = 0;
      strcat( data, "t=something+smells!+air+quality+" );
      char ss[4] = "";
      itoa( smell, ss, 10 );
      strcat( data, ss );
      strcat( data, "&c=" );
      strcat( data, consumer_secret );
      strcat( data, "&a=" );
      strcat( data, access_token_secret );
      tweet( data );
      lastAlerted = millis( ); 
    }    
    delay( 1000 );
  }
}

void tweet ( char *data ) {
  post( tweetHost, tweetPath, data );
}

void post ( char *host, char *path, char *data ) {
  Serial.println( data );  
  if ( client.connect( host, 80 )) {
    delay( 100 );
    client.flush( );
    client.print( "POST " );
    client.print( path );
    client.print( "?_=" );
    client.print( millis( ));
    client.println( " HTTP/1.1" );
    client.print( "Host: " );
    client.println( host );
    client.println( "User-Agent: Arduino/1.0" );
    client.println( "Content-Type: application/x-www-form-urlencoded" );
    client.print( "Content-length: " );
    client.println( strlen( data ));
    client.println( "Connection: close" );
    client.println( );
    client.println( data );
    client.stop( );
  }
  else {
    Serial.print( "failed to connect to " );
    Serial.println( host );
  }
}

void log ( byte *msg, byte len ) {
  if ( compare( msg, lastCommand, 0, len )) {
    // Serial.println( "msg + lastCommand were the same" );
    return;
  }
  for ( int i = 0; i < len; ++i ) {
    lastCommand[i] = msg[i];
  }
    
  char data[128];
  data[0] = 0;
  strcat( data, "t=" );
  strcat( data, device( msg ));
  strcat( data, "+sent+" );
  strcat( data, command( msg ));
  strcat( data, "&c=" );
  strcat( data, consumer_secret );
  strcat( data, "&a=" );
  strcat( data, access_token_secret );
  tweet( data );
}

/**
 * get a useful string out of an array of bytes
 */
char * tos ( byte *msg, int start, int end ) {
  char * name = "";
  int index = 0;
  for ( int i = start; i < end; i ++ ) {
    name[index++] = alpha( msg[i] );
  }
  name[index++] = '\0';
  return name;
}

/**
 * get a command string from response
 */
char * command ( byte *msg ) {
  return tos( msg, 0, 4 );
}

/**
 * get device name from response
 */
char * device ( byte *msg ) {
  byte b[6] = { 0x00, 0x0D, 0x0C, 0x02, 0x08 };
  if ( compare( msg, b, 5, 10 )) {
    return "remote b";
  }
  return tos( msg, 4, 9 );
}

/**
 * turn a hex value into char for display, like sprintf
 */
char alpha ( byte a ) {
  return (char)( a < 10 ? a + 48 : a + 55 );
}

boolean compare ( byte a[], byte b[], int start, int end ) {
  for ( int i = start; i < end; ++ i ) {
    if ( a[i] != b[i] ) return false;
  }
  return true;
}

It doesn't post directly to twitter from this sketch, but rather via a web proxy I have hosted somewhere The first time it runs all is fine, it gets a result and posts to http://twitter.com/ourduino but after that just silence.

I see a lot of strings in there, you may be running out of RAM. You may wish to start using the F() macro to store some of those in FLASH instead:

I knew there was something I was meant to be using instead of just dropping strings everywhere but thought I'd come back to it later... I'll give that a try.

That's great, that's what it was... I was just about to lazily post "Is there a way of spotting when I'm running out of memory during run time?" but wait, let me google that for me... from Arduino Playground - AvailableMemory

int freeRam () {
  extern int __heap_start, *__brkval; 
  int v; 
  return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); 
}

Thanks again.

Have you noticed when you connect to this site...
http://twitter.com/ourduino
...you get this one.
https://twitter.com/ourduino

That is a SSL server. The ethernet library does not support SSL (https). This is the redirect you should get from the twitter site now.

HTTP/1.1 301 Moved Permanently
date: Fri, 30 Aug 2013 03:01:12 UTC
location: https://twitter.com/arduino
server: tfe
set-cookie: guest_id=v1%3A137783167277866638; Domain=.twitter.com; Path=/; Expires=Sun, 30-Aug-2015 03:01:12 UTC
Content-Length: 0
Connection: close

I'm posting from the arduino to my own proxy, I know it works, see all the posts on http://twitter.com/ourduino already...

I can't get there with my web browser without being redirected to the https site. When I try, the address bar shows this:
https://twitter.com/ourduino

I'll have to try with my Arduino when it is finished with the server test.

SurferTim:
I can't get there with my web browser without being redirected to the https site. When I try, the address bar shows this:
https://twitter.com/ourduino

I'll have to try with my Arduino when it is finished with the server test.

Do you have a proxy server like paulypopex?

You must forgive me, but what does a proxy server (port 80) have to do with https (port 443)?

Proxy server can run on any port you like, and make an outgoing SSL connection on the clients behalf.

tylernt:
Proxy server can run on any port you like, and make an outgoing SSL connection on the clients behalf.

An outgoing SSL connection. The ethernet library does not support SSL. I do understand there are some services that translate the http connection to the translator to a SSL connection from the translator to twitter. Is that what you mean? Here is a mention of that type service in this post.
http://forum.arduino.cc/index.php?topic=195135.msg1440885#msg1440885

Yes, a proxy can take a non-SSL client connection and translate it into an SSL connection headed elsewhere.

I say a "proxy" it's really just a web hosted script that I wrote that I post too from my arduino (just over http) which then makes a similar but different (more params, longer query string, signed, and over https) post to twitter.com.

https://twitter.com/ourduino is just a page where you can go to see the output, it's not the page I post to.

Good deal! What does the twitter server return when the post is successful? What does it return when it fails?

what the server responds is not relevant to my issue here, which is now solved

paulypopex:
what the server responds is not relevant to my issue here, which is now solved

That is only your perception. If you are not monitoring what the server sends, your problems have just started.

see here Documentation Home | Docs | Twitter Developer Platform

my request that I send to my own server is in my original post, or see the repo for updates. I'm responding with 200 and just OK! at the moment, as I'm not interested in the response.

If you're really interested, a sample request sent to my script looks something like

POST /tweet?_=123456788 HTTP/1/1
Host: www.foo.com
User-Agent: Arduino/1.0
Content-Type: application/x-wwwform-urlencoded
Content-length: 8
Connection: close

foo=bar

This reminds me I have another issue, for another thread... If I send a request like that to a simple script that just parses those params and then does something with them all is fine, but if I send the same request to a Sinatra based script, sinatra errors with just '!! invalid request'... another problem for another post / forum.

Here is your original code. Where are you reading the response from the server? This code has no idea what transpired at your translator. If you are sending pass/fail from the translator to the Arduino, you should at least read it.

  if ( client.connect( host, 80 )) {
    delay( 100 );
    client.flush( );
    client.print( "POST " );
    client.print( path );
    client.print( "?_=" );
    client.print( millis( ));
    client.println( " HTTP/1.1" );
    client.print( "Host: " );
    client.println( host );
    client.println( "User-Agent: Arduino/1.0" );
    client.println( "Content-Type: application/x-www-form-urlencoded" );
    client.print( "Content-length: " );
    client.println( strlen( data ));
    client.println( "Connection: close" );
    client.println( );
    client.println( data );
    client.stop( );
  }