what you mean don't use string?
Never, not ever, shalt thou use String
for anything. Not for arguments, not for variables, not for API key, not a thing. You will save at least 1600 bytes of flash and untold hours of debugging when it stops working "bizarrely".
Why do this:
String writeAPIKey = "XXXXXXXXXXXXXX";
.
.
.
client.print("X-THINGSPEAKAPIKEY: "+writeAPIKey+"\n");
...instead of this:
client.print("X-THINGSPEAKAPIKEY: XXXXXXXXXXXXXX\n");
A total waste. Not only that, you are using RAM for all these character string constants (not String
s). You should be using the F
macro:
client.print( F("X-THINGSPEAKAPIKEY: XXXXXXXXXXXXXX\n") );
The problem with String
and the way you are using it is that it will eventually fragment the dynamic memory "heap", and further String
operations will fail, causing weird behavior wherever the sketch needs characters from those String
. But the failure will happen at different times if you have different string values and operations. Bad juju. Determinism is your friend.
Use char
arrays for things that are really textual and that change (there aren't any in your program, as thingSpeakAddress
must remain a RAM char *
).
Or just use the F
macro in calls that can take PROGMEM strings, like Serial.print
or client.print
. If a constant text snippet is used in multiple places, you can declare a truly constant char array with
const char varname[] PROGMEM = "for text that never changes.";
Using it is a little different if you're not just passing it to print
. The field name for Power
is an example of that.
In general, keep "variable" values in their integer or floating-point form until the last possible part of the sketch, then "convert" it to text with print
or itoa
or whatever. The Power
variable is a good example of this. The numeric forms are almost always smaller than their character representation, so you will end up saving even more RAM.
Here is your sketch with those suggested modifications:
#include <SPI.h>
#include <Ethernet.h>
// Local Network Settings
byte mac[] = { 0x00, 0xAA, 0xBB, 0xCC, 0xDE, 0x01 }; // Must be unique on local network
// ThingSpeak Settings
char thingSpeakAddress[] = "api.thingspeak.com";
const int updateThingSpeakInterval = 16 * 1000; // Time interval in milliseconds to update ThingSpeak (number of seconds * 1000 = interval)
// Variable Setup
long lastConnectionTime = 0;
boolean lastConnected = false;
int failedCounter = 0;
//Heat Meter Variable Setup
float Volt_low = 184;
float Volt_high = 787;
float kW_low = 0;
float kW_high = 16.299;
float Power;
int analogue1; //Analogue 1 is A1
const char powerFieldName[] PROGMEM = "field1";
// Initialize Arduino Ethernet Client
EthernetClient client;
void setup()
{
// Start Serial for debugging on the Serial Monitor
Serial.begin(9600);
//Disable SD Card
digitalWrite(4,HIGH);
// Start Ethernet on Arduino
while (startEthernet()== 0) {
delay(1000);
}
}
void loop()
{
// Read value from Analog Input Pin 0
analogue1 = analogRead(1);
Power = (analogue1 - Volt_low) * ((kW_high - kW_low) / (Volt_high-Volt_low));
delay(5); // Pause for 5 ms.
while (client.available())
{
char c = client.read();
Serial.print(c);
}
// Disconnect from ThingSpeak
if (!client.connected() && lastConnected)
{
Serial.println( F("...disconnected\n") );
client.stop();
}
// Update ThingSpeak
if (!client.connected() &&
(millis() - lastConnectionTime > updateThingSpeakInterval))
{
char powerChars[16];
dtostrf( Power, 5, 2, powerChars );
Serial.println( F("Updating ThingSpeak") );
Serial.print( powerFieldName );
Serial.print( '=' );
Serial.println( powerChars );
updateThingSpeak( powerFieldName, powerChars );
}
// Check if Arduino Ethernet needs to be restarted
if (failedCounter > 3 ) {
failedCounter = 0;
while (startEthernet()==0 ) {
delay(1000);
}
}
lastConnected = client.connected();
}
void updateThingSpeak( PGM_P fieldName, char *value )
{
if (client.connect(thingSpeakAddress, 80))
{
client.println( F("POST /update HTTP/1.1") );
client.println( F("Host: api.thingspeak.com") );
client.println( F("Connection: close") );
client.println( F("X-THINGSPEAKAPIKEY: XXXXXXXXXXXXX") );
client.println( F("Content-Type: application/x-www-form-urlencoded") );
client.println( F("Content-Length: ") );
client.println( strlen_P(fieldName) + 1 + strlen(value) );
client.println();
client.print( fieldName );
client.print( '=' );
client.print( value );
lastConnectionTime = millis();
if (client.connected())
{
Serial.println( F("Connecting to ThingSpeak...\n") );
failedCounter = 0;
}
else
{
failedCounter++;
Serial.print( F("Connection to ThingSpeak failed (") );
Serial.print( failedCounter );
Serial.println( ')' );
Serial.println();
}
}
else
{
failedCounter++;
Serial.print( F("Connection to ThingSpeak failed (") );
Serial.print( failedCounter );
Serial.println( ')' );
Serial.println();
lastConnectionTime = millis();
}
}
int startEthernet()
{
client.stop();
Serial.println( F("Connecting Arduino to network...\n") );
delay(1);
// Connect to network and obtain an IP address using DHCP
if (Ethernet.begin(mac) == 0)
{
Serial.println( F("DHCP Failed\n") );
return 0;
}
else
{
Serial.print( F("Arduino connected to network using DHCP IP:") );
Serial.println(Ethernet.localIP());
Serial.println();
return 1;
}
delay(1);
}
Be sure to compare the program space and RAM numbers before and after these changes. (It compiles, but I can't test it.)
Cheers,
/dev