Web server for Classic using Arduino DUE

Started by dgd, March 12, 2015, 01:00:24 AM

Previous topic - Next topic

dgd

To get the simple web server working with an Arduino DUE some library changes are required plus the hardware interface for rs232 needs reworking.
The Arduino DUE is a more resourced computer based on the ATmel 32bit SAM3X8e ARM Cortex M3 processor running at 84Mz.  Ram is 96k, and flash 512k. Compared to the UNO with 16Mhz 8 bit ATmel328 cpu, 32k flash and 2k ram, this Arduino has the potential to make a quite nice web server system for a Classic.
With all that available ram a decent sized data structure can be used to store hours and even days of Classic data. This could be used to provide a series of web pages and simple graph displays. It could be backed onto a Sandisk SD card intreface that is a standard fitting on the ethernet shield.

The DUE is a 3.3volt system so interfaces to the various digital connections have to be max 3.3v
The Wiznet 5100/5200 based ethernet shield is fully compatible with the DUE.
However, the rs232 shield is not as it is a 5volt TTL level card (the MAX232 onboard needs 5v for its voltage pump circuit to provide rs232 signal voltage levels). It also interfaces to the serial pins digital 0 and 1 which are used on the DUE to provide a USB port.
So one of the other serial pin sets, serial1, serial2 and serial3 needs to be used.
Connecting 5v to any of the DUE 3.3v pins will damage the cpu.

To get the Classics rs232 connected to a serial port on the DUE I used a teensy sized max232 board and wired it to the serial1 port (on digital pins 18 (tx1) and 19 (rx1). The problem is these digital pins operate at 3.3v and the output from the max232 card is 5v.
The tx1  pin is not a problem as the max232 can work with 3.3v signal levels so the tx can be directly wired to the max232. The issue is with the rx on the DUE nd the 5v output from the max232 needs to be level shifted so as not to kill the rx1 input.
The easiest way to do this was with a resistor divider network.
I used a 500 ohm and 1k ohm resistors for this.

Works perfectly and allows Classic rs232 data into the DUE
Image shows DUE with ethernet shield and at back the max232 pcb on a proto shield

dgd

Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

dgd

To get the simple web server compiled for the DUE needs some changes.

First the sketch needs the call to modbus_configure slightly changed -
from
  modbus_configure(&Serial, baud, SERIAL_8N1, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
to
  modbus_configure(&Serial1, baud, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);

The DUE does not use the byteFormat parameter SERIAL_8N1 and the port address pointer is changed to $Serial1

Second, and a tad more complicated the libs for SimpleModbusMaster need some changes.
Go to the SimpleModbusMaster lib directory   -   on my Win8 laptop this is at:
> This PC > Documents> Arduino > libraries > SimpleModbusMasterv10

Two files need to be edited (I used Notepad editor)
SimpleModbusMaster.h
Search for

void modbus_configure(HardwareSerial* SerialPort,
                                 long baud,
                                 unsigned char byteFormat,
                                 unsigned int _timeout,
                                 unsigned int _polling,
                                 unsigned char _retry_count,
                                 unsigned char _TxEnablePin,
                                 Packet* _packets,
                                 unsigned int _total_no_of_packets);

and comment out the line
//                                                                                      unsigned char byteFormat
then save the file

Edit the file SimpleModbusMaster.cpp

find the lines

void modbus_configure(HardwareSerial* SerialPort,
                                 long baud,
                                 unsigned char byteFormat,
                                 unsigned int _timeout,
                                 unsigned int _polling,
                                 unsigned char _retry_count,
                                 unsigned char _TxEnablePin,
                                 Packet* _packets,
                                 unsigned int _total_no_of_packets)
{

Comment out the line
//                                                                                       unsigned char byteFormat,

then look for line further down this function

   (*ModbusPort).begin(baud, byteFormat);

comment it out

//     (*ModbusPort).begin(baud, byteFormat);

and insert below it

       (*ModbusPort).begin(baud);   


then save the cpp file.

The sketch for the simple web server should now compile and load onto the DUE

dgd
Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

dgd

#2
The next step with the DUE is to extend the sketch to provide more web page detail and reporting plus provide some auxiliary switching options.

This has been brought about by a local client who has a Classic Lite with WBjr and although he uses the local app when on site he asked for web access for him and his staff when off site. One tcp connection just proves too difficult to manage and anyway does not work on iPhone/iPad.

The DUE's digital pins are easy to connect to minuature relays such as the dual relay board in pic and controlling these using register data from Classic is straightforward.

The more interesting application is using the PWM output from the DUE to control an SSR for water heating. The Classic aux2 was used for this before the WBjr took away the aux2 so the waste not control should be possible with the DUE.
The Classic waste not appears to start the pwm signalling at a defined set point below the Absorb voltage and by the time the absorb voltage is reached the load is fully switched in circuit.
This does work but needs some careful design of the load so that there is sufficient power to drive it and keep the battery charging in Absorb stage.
PWMing a large load into circuit could cause charging to drop out off Absorb or even prevent the classic from reaching Absorb
(Unless I haveI misunderstood how this waste-not works?)

So with the DUE I planned the use of PWM slightly differently.
Only when the classic reaches absorb then will the PWM start and on each voltage register read (or charge state register read) the PWM will be adjusted/stepped to a higher duty cycle. If voltage/state drops below absorb voltage the duty cycle reduces.
I can't see any major problems with this approach but maybe there are issues I don't yet see.

The simple improved web page can show a list of various data from the Classic every 10 minutes.
A simple data structure of records, time stamped, is held in memory for 48 hours of data.
I will post the sketch for this soon.
Just investigating some simple bar graphs as a web page option.

Dgd

Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

Westbranch

Quoteusing the PWM output from the DUE to control an SSR for water heating.

Dgd, is this for DC heating elements? or AC?
KID FW1811 560W >C&D 24V 900Ah AGM
CL150 29032 FW V.2126-NW2097-GP2133 175A E-Panel WBjr, 3Px4s 140W > 24V 900Ah AGM,
2 Cisco WRT54GL i/c DD-WRT Rtr, NetGr DS104Hub
Cotek ST1500 Inv  want a 24V  ROSIE Inverter
OmniCharge3024  Eu1/2/3000iGens
West Chilcotin 1680+W to come

dgd

Quote from: Westbranch on March 12, 2015, 11:07:33 PM
Quoteusing the PWM output from the DUE to control an SSR for water heating.

Dgd, is this for DC heating elements? or AC?

It should work for both since it depends on the relay - either an AC ssr or DC ssr

Dgd
Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

Westbranch

 :)  tks for the clarification, let us know if it works as planned...
KID FW1811 560W >C&D 24V 900Ah AGM
CL150 29032 FW V.2126-NW2097-GP2133 175A E-Panel WBjr, 3Px4s 140W > 24V 900Ah AGM,
2 Cisco WRT54GL i/c DD-WRT Rtr, NetGr DS104Hub
Cotek ST1500 Inv  want a 24V  ROSIE Inverter
OmniCharge3024  Eu1/2/3000iGens
West Chilcotin 1680+W to come

dgd

#6
Dual rs232 on proto shield for DUE, to connect two Classics to DUE web server. Maximum of 4 Classics could be connected. Modified simple web server sketch next post.
Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

paul alting

Nice write up dgd,

I see form the last photo you have a Freetronics ProtoShield, are you in Australia then, as these boards are made down here?

Currently I run a  Freetronics EtherMega (think Mega plus onboard Ethernet and SD) which has a switching supply rather than standard linear as used by most Arduino boards.
My setup is such that the Arduino controlls an AC SSR which I use as a diversion load controller to dump excess exnergy from my micro-hydro turbine.
I put in a PID loop comtroller routine that maintains my battery bank setpoint, at around 27.4 Volts.

Initially my program much like how you described, where I used the HTTP server library, Webduino, which really is a nicely structured library.
And it worked for some time and has been useful while I am over in Europe, allowing me to check in and see the system.

Then I started thinking more about it and also the probelms with the Wiznet-5100, in that it only allows 4 TCP connections, and for quite some time, there has been an ongoing problem with the Ethernet library, in that sometimes. connections were not released by the software. This problem has only been recently looked into and rectified, by some of the other folks on the Arduino forum, such as SurferTim.

With this, I moved away from having the Arduino acting as a HTTP server in itself, and instead started down the process of splitting the system into 2 parts.
Having Arduino as my interface to sensors and output devices and doing low level I/O things as the first part and then using somehting like a Cubieboard to play the part of HTTP server and all things higher level.

The DUE does bring a lot more resources to play with, but it is unfortunate that the designers of the board did not really do the best job.
For example, the SAM8E has onboard EMAC hardware for nice high speed Ethernet connectivity, but none of that is available on the standard DUE.

This is where the folks at Electhouse made a DUE with these pins brought out, called the Taijuino.
I was given some of these boards by Elechouse in the hope a native Ethernet library could be developed in conjunction with two other programmers.
Having such an Ethernet interface would not have the issues that the Wiznet gives, where the Wiznet is slow, it depends on SPI and has limited concurrent TCP connections sockets.
Unfortunately, to date, the DUE Ethernet library has not been completed.

I am currently moving my whole project from the Freetronics EtherMega to Taijuino DUE, with a whole lot more, in terms of sensors and features.
It will also be my solar charge controller, where I will control 6 indepenant high power MOSFETS in an interleaved PWM fashion.
I have a nice 3.2" LCD with touch panel from buydisplay that will give basic live data and status information.

With the DUE, we have an ADC that is capable of 12 bits rather than 10bits as found on AVR boards.

I guess I have a question;
If you have an Arduino with Ethernet interface, why not then talk to your Classic via TCP, rather than RS-232?
I don't yet know the Classic charge controllers well, not having one, but only reading the documents.
The reason I ask is, I am working with a guy in the states who does have two and I am helping him setup a full off-grid monitoring system.

Does this forum have code tags for your code to be displayed better?
I'll be interested to read more :)
____
Paul
6 x 200W PV into home-brew 6 stage MOSFET charge controller : Microhydro 220Vac 3 phase IMAG
8 x 400Ah LiFeYPO4 Winston : Latronics LS2412 inverter
QuadlogSCADA control and monitoring system : Tasmania, Australia : http://paulalting.com

dgd

#8
Paul,

I'm in NZ where freetronics stuff is available from Jaycar. I would have liked a freetronics ether mega but the price at $150 is just crazy compared to a mega+ethernet shield for about $40.
As for Wiznet5100/5200 controllers I have not had any issues although I have read about some of the problems others have identified.

At one site I support we use a $5 uno and $12 rs232 shield to control a Crydom SSR for water heating using a PWM output and a couple of digital outputs for ventilation fan and night light.
The Uno connects to a Classic Lite 150 and pulls a few modbus register values for heating and lighting control. (I will post sketch and photos here soon).

My plan is not to go too far with developing the DUE for web access although the tiny web server installed and runs good. I liked the upload and serving of pages from the SD card.
However its all getting pretty complicated for the DUE as I also wanted to get three serial ports used to connect Classics.
I prefer simple solutions and after experimenting with rs485-rs232 converters on Classics
this approach was abandoned due to awful throughput rate.

Now, after buying a Cubie2, installing Linux and proper web server (and an SSD for proper data storage ) , I want to have each Classic connected via rs232 modbus to a mega2560
simply to manage raw data acquistion and then periodically transfer this data to the Cubie.
Ethernet or more likely I2C - since both Cubie and megas support this.

In meantime I have connected a 5v nano ($2 from Ebay) with one of the tiny max232 cards and have the nano using I2C to transfer Classic data to a DUE. Works perfectly and lets me make a simple web page to display data from two Classics individually and integrated into an overall set of data totals.

As for your question about why not use ethernet for Arduino to Classic comms ;)
Because basically the Classic's ethernet is not reliable and is limited to just one user TCP connection. There is a second but that is reserved for the MyMidnite server connection, is encrypted and MN do not provide either encryption details or the abililty to configure it for alternate use.
There are others in this forum who use ethernet to Classic to extract and process data.

Anyway, will be interested in your progress..

dgd
Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

dgd

#9
The simple web server code now updated to allow up to four Classics to be connected to the four serial ports of an Arduino Mega or Arduino DUE.
Although still using the SimpleModbusMaster library, which is designed for an rs485 bus where more than one slave device is connected to a master device OR only one rs232 slave device.
The sketch simply uses a time based round robin method to restart the (mis-named) modbus state engine with a different physical serial port.
This method works well enough to extract modbus data from several connected Classics but
the real solution would be to dump the lib or hack it down to just support Read-holding-registers and forget the state machine concept (the docs say it runs in background but thats
sure not true on a single non scheduled processor).

The DUE firmware supports  a simple program scheduler system so the possibilities are there to deal with multiple modbus readers each processing a Classic on its own rs232 port.

There are too many changes to the simple web server code to list so whole sketch posted in next message.
This is running on a DUE with the small rs232  serial port cards shown on Freetronics proto shield in previous posting. An additional small chopped down shield with one further serial port was also attached to the DUE to provide three rs232 ports for testing.

dgd
Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

dgd

#10
This arduino sketch is for a DUE and needs multiple serial rs232 ports, one for each Classic connection.
The code is not very sophisticated and the lack of formatted print support means multiple simple print statements.
Compiled using IDE 1.6.1 and SimpleModbusMaster library v10 with mods as listed at start of this subject thread.

Cut and paste into IDE and check for split and truncated lines of text/code

dgd

---


/*
  Web Server

A simple web server that shows the values of several modbus registers from Midnite
Classic. Up to 4 Classics conected via separate rs232 connection to Arduino Mega or DUE
David Dix  20 March 2015  dgd@kc.net.nz
*/

#include <SimpleModbusMaster.h> 
#include <Ethernet.h>
#include <SPI.h>

// Enter a MAC address and IP address for your controller below.
// The IP address will be dependent on your local network:
byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 177);

// Initialize the Ethernet server library
// with the IP address and port you want to use
// (port 80 is default for HTTP):
EthernetServer server(80);

// setup modbus port information
#define baud 19200
#define timeout 1000
#define polling 200 // the scan rate
#define retry_count 10
#define IDLE 1
#define CLTIME 15000

// used to toggle the receive/transmit pin - only for rs485
#define TxEnablePin 2

// up to 4 Classics connected the serial ports (Mega and DUE)
#define CLASSICS 2

enum
{
  PACKET1,
  PACKET2,
  PACKET3,
  PACKET4,
  PACKET5,
  TOTAL_NO_OF_PACKETS // leave this last entry
};

// Create an array of Packets to be configured
Packet packets[TOTAL_NO_OF_PACKETS];
packetPointer packet1 = &packets[PACKET1];  // pointers to access each packet
packetPointer packet2 = &packets[PACKET2];
packetPointer packet3 = &packets[PACKET3];
packetPointer packet4 = &packets[PACKET4];
packetPointer packet5 = &packets[PACKET5];

// Data read from the Classic will be stored in these arrays, using separate arrays to keep memory usage low
// if the array is initialized to the packet.
unsigned int readRegs[30];
unsigned int wbjrRegs[15];
unsigned int vRegs[2];
unsigned int idRegs[10];       // name 4209 to 4212, and time/date 4213 to 4216
unsigned int sernoRegs[2];

HardwareSerial* serialPort;


int current_classic = 0, prev_classic;

  float batt_volts[CLASSICS], in_volts[CLASSICS], batt_amps[CLASSICS], kwh[CLASSICS];
  float high_in_volts[CLASSICS], wbjr_amps[CLASSICS];
  int   cstate[CLASSICS], watts[CLASSICS], wbjr_soc[CLASSICS], vers[CLASSICS], model[CLASSICS];
  float fet_temp[CLASSICS], pcb_temp[CLASSICS], rem_temp[CLASSICS], bat_temp[CLASSICS];
  char  Classic_name[CLASSICS][10];
  int   eq_hrs[CLASSICS], eq_mins[CLASSICS], eq_secs[CLASSICS];
  int   fl_hrs[CLASSICS], fl_mins[CLASSICS], fl_secs[CLASSICS];
  int   abs_hrs[CLASSICS], abs_mins[CLASSICS], abs_secs[CLASSICS];
  int   serno[CLASSICS], rcheck[CLASSICS];
  unsigned long start_count, timenow;

void setup()
{
  int  i,j, k;
 
  // start the Ethernet connection and the server:
  Ethernet.begin(mac, ip);
  server.begin();
   
  modbus_construct(packet1, 10, READ_HOLDING_REGISTERS, 4114, 29, readRegs);
  modbus_construct(packet2, 10, READ_HOLDING_REGISTERS, 4360, 14, wbjrRegs);
  modbus_construct(packet3, 10, READ_HOLDING_REGISTERS, 4100, 1, vRegs);
  modbus_construct(packet4, 10, READ_HOLDING_REGISTERS, 4209, 9, idRegs);
  modbus_construct(packet5, 10, READ_HOLDING_REGISTERS, 0x7000, 2, sernoRegs);
 
  // initilise classic data arrays
  for (k=0; k < CLASSICS; k++ )   // initial all values
   { 
     batt_volts[k] = 0;
     in_volts[k] = 0;
     batt_amps[k] = 0;
     kwh[k] = 0;
     high_in_volts[k] = 0;
     cstate[k] = 0;
     watts[k] = 0;
     wbjr_soc[k] = 0;
     wbjr_amps[k] = 0;
     vers[k] = 0;
     model[k] = 0;
     for (j=0; j<10; j++)
       Classic_name[k][j] = 0x00;
     fet_temp[k] = pcb_temp[k] = rem_temp[k] = bat_temp[k] = 0;
     serno[k]=0;
     
   }

   start_count = millis();
   modbus_configure(&Serial1, baud, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
}

void loop()
{
  char  c;
  int   i,j,k;


/*
   Use millis() time counting for changing between Classics being processed by the modbus state machine.
   Each change just pokes the harware serial parameter and re-executes modbus_configure/modbus_update.
   Not perfect but seems to work, may take an iteration or three to get the correct readings in each
   display column.
   Proper solution is to rewrite less sophisticated modbus lib and execute one modbus manager for each
   serial port - using the DUE scheduler would work well for this method     
     
*/
   prev_classic = current_classic;

   timenow = millis();
   if ((timenow - start_count) > (unsigned long)CLTIME)
   {
     start_count = timenow;
     current_classic++;
     if (current_classic >= CLASSICS) current_classic = 0;
     switch (current_classic)
     {
       case 0:
          serialPort = &Serial1;
          break;
       case 1:
          serialPort = &Serial2;
          break;
       case 2:
          serialPort = &Serial3;
          break;
       case 3:
          serialPort = &Serial;     // hardware serial 0
          break;
     }
     if (current_classic != prev_classic )
     {
       modbus_configure(serialPort, baud, timeout, polling, retry_count, TxEnablePin, packets, TOTAL_NO_OF_PACKETS);
       modbus_update();
       delay(10);
     }
   }
 
   modbus_update();
   
   k = current_classic;
   
  // make Classic register values ready for web page
     model[k] = (unsigned int)lowByte(vRegs[0]);
     serno[k] = sernoRegs[1];
     rcheck[k] = sernoRegs[1];
     Classic_name[k][0] = lowByte (idRegs[0]);
     Classic_name[k][1] = highByte(idRegs[0]);
     Classic_name[k][2] = lowByte (idRegs[1]);
     Classic_name[k][3] = highByte(idRegs[1]);
     Classic_name[k][4] = lowByte (idRegs[2]);
     Classic_name[k][5] = highByte(idRegs[2]);
     Classic_name[k][6] = lowByte (idRegs[3]);
     Classic_name[k][7] = highByte(idRegs[3]);
     Classic_name[k][8] = 0x00;

     batt_volts[k] = readRegs[0];
     batt_volts[k] /=10;
     in_volts[k] = readRegs[1];
     in_volts[k] /=10;
     batt_amps[k] = readRegs[2];
     batt_amps[k] /=10;
     kwh[k]= readRegs[3];
     kwh[k] /=10;
     watts[k] = readRegs[4];
     cstate[k] = (unsigned int)readRegs[5] >> 8;  // high byte contains charge state code 
   
     high_in_volts[k] = readRegs[7];
     high_in_volts[k] /=10;
     bat_temp[k] = readRegs[17];    // need to test if BTS present
     bat_temp[k] /=10;
     fet_temp[k] = readRegs[18];
     fet_temp[k] /=10;
     pcb_temp[k] = readRegs[19];
     pcb_temp[k] /=10;
     
     fl_secs[k] = readRegs[23];      //4137 floatTimeodayseconds
     if (fl_secs[k] >= 3600) fl_hrs[k] = (int)fl_secs[k]/3600;
     fl_secs[k] -= fl_hrs[k]*3600;
     if (fl_secs[k] >= 60 ) fl_mins[k] = (int)fl_secs[k]/60;
     fl_secs[k] -= fl_mins[k]*60;
     
     eq_secs[k] = readRegs[28];      //4142 EqualizeTime
     if (eq_secs[k] >= 3600) eq_hrs[k] = (int)eq_secs[k]/3600;
     eq_secs[k] -= eq_hrs[k]*3600;
     if (eq_secs[k] >= 60 ) eq_mins[k] = (int)eq_secs[k]/60;
     eq_secs[k] -= eq_mins[k]*60;
     
     abs_secs[k] = readRegs[24];      //4138 AbsorbTime
     if (abs_secs[k] >= 3600) abs_hrs[k] = (int)abs_secs[k]/3600;
     abs_secs[k] -= abs_hrs[k]*3600;
     if (abs_secs[k] >= 60 ) abs_mins[k] = (int)abs_secs[k]/60;
     abs_secs[k] -= abs_mins[k]*60;
     
     rem_temp[k] = (unsigned int) lowByte (wbjrRegs[11]);
     rem_temp[k] -=50;
     j = (signed int)wbjrRegs[10];    // change from unsigned int in wbjrRegs to int in j then to float
     wbjr_amps[k] = j;
     wbjr_amps[k] /=10;
     wbjr_soc[k] = wbjrRegs[12];          // 4372

 
  // listen for incoming clients
  EthernetClient client = server.available();
  if (client)
  {
    // an http request ends with a blank line
    boolean currentLineIsBlank = true;
    while (client.connected())
    {
      if (client.available())
      {
        char c = client.read();
        // if you've gotten to the end of the line (received a newline
        // character) and the line is blank, the http request has ended,
        // so you can send a reply
        if (c == '\n' && currentLineIsBlank)
        {
          // send a standard http response header
          client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");

          client.println("<html><body>");
         
          // simple page title
          client.print ("<h2>Midnite Classic </h2>");

          client.println ("<table border=\"1\" cellpadding=\"10\" style=\"width\:70%\"\>");
         
          client.println ("<tr>");         
          client.println ("<td>Name</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print (Classic_name[k]);
             client.print (" C");
             client.print (model[k]);
             client.print (" #");
             client.print (serno[k]);     // classic serial number
             client.println("</td>");
          }
          client.println("</tr>");
         
          client.println("<tr>");         
          client.print ("<td>Charge State</td>");
          for (k=0; k< CLASSICS; k++ )
          {
            switch (cstate[k])
            {
            case 0:
              client.print ("<td>Resting</td>");
              break;
            case 3:
              client.print ("<td>Absorb - time left ");
              client.print (abs_hrs[k]);
              client.print (":");
              client.print (abs_mins[k]);
              client.print (":");
              client.print (abs_secs[k]);
              client.print ("</td>");
              break;
            case 4:
              client.print ("<td>BulkMppt</td>");
              break;
            case 5:
              client.print ("<td>Float - total time ");
              client.print (fl_hrs[k]);
              client.print (":");
              client.print (fl_mins[k]);
              client.print (":");
              client.print (fl_secs[k]);
              client.print ("</td>");
              break;
            case 6:
              client.print ("<td>FloatMppt</td>");
              break;
            case 7:
              client.print ("<td>Equalize - time left ");
              client.print (eq_hrs[k]);
              client.print (":");
              client.print (eq_mins[k]);
              client.print (":");
              client.print (eq_secs[k]);
              client.print ("</td>");

              break; 
            case 10:
              client.print ("<td>HyperVoc</td>");
              break;
            case 18:
              client.print ("<td>EqMppt</td>");
              break;
            }
          }
          client.println("</tr>");
         
          client.println("<tr>");
          client.print("<td>Battery volts</td>");
          for (k=0; k< CLASSICS; k++ )
          {       
             client.print("<td>");
             client.print(batt_volts[k]);
             client.println("</td>");
          }
          client.println ("</tr>");
         

          client.println("<tr>");
          client.print ("<td>Output Amps</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print(batt_amps[k]);
             client.println("</td>");
          }
          client.println ("</tr>");

          client.println("<tr>");
          client.print ("<td>Power Watts</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print(watts[k]);
             client.println("</td>");
          }
          client.println("</tr>");
 
          client.println("<tr>");
          client.print ("<td>Energy Kwhr</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print(kwh[k]);
             client.println("</td>");
          }
          client.println("</tr>");
         
          client.println("<tr>");
          client.print("<td>InputPV volts</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print(in_volts[k]);
             client.println("</td>");
          }
          client.println("</tr>");
         
          client.println("<tr>");
         
          client.print("<td>High PV volts</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print(high_in_volts[k]);
             client.println("</td>");
          }
          client.println("</tr>");
         
          client.println("<tr>");
          client.print("<td>PCB temp oC</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print(pcb_temp[k]);
             client.println("</td>");
          }
          client.println("</tr>");

          client.print("<tr>"); 
          client.print("<td>FET temp oC</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print(fet_temp[k]);
             client.println("</td>");
          }
          client.println("</tr>");
         
          client.println("<tr>");
          client.print("<td>BAT temp oC</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             if (bat_temp[k] > 100 )
              client.print ("(25c)");
             else
              client.print(bat_temp[k]);
             client.println("</td>");
          }
          client.println("</tr>");
         
          client.println("<tr>");
          client.print("<td>Remote temp oC</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             if (rem_temp[k] == -50)  // no wbjr connected
               client.print ("-");
             else
               client.print(rem_temp[k]);
             client.println("</td>");
          }
          client.println("</tr>");
         
          client.println("<tr>");
          client.print ("<td>WBjr Amps</td>");
          for (k=0; k< CLASSICS; k++)
          {
             client.print ("<td>");
             if (rem_temp[k] == -50)  // no wbjr connected
               client.print ("-");
             else
             {
               if (wbjr_amps[k] > 6000) wbjr_amps[k] -= 6553;
               client.print(wbjr_amps[k]);
             }
             client.println ("</td>");
          }
          client.println("</tr>");
   
          client.println("<tr>");
          client.print ("<td>Battery SOC%</td>");
          for (k=0; k< CLASSICS; k++ )
          { 
             client.print ("<td>");
             if (rem_temp[k] == -50)
               client.print ("-");
             else
               client.print(wbjr_soc[k]);
             client.println ("</td>");
          }
          client.println("</tr>");
           
          client.println ("</table>");

          client.println("</body></html>");
          break;
        }
        if (c == '\n') {
          // you're starting a new line
          currentLineIsBlank = true; 
         
        }
        else if (c != '\r') {
          // you've gotten a character on the current line
          currentLineIsBlank = false;
        }
      }
    }
    // give the web browser time to receive the data
    delay(10);
    // close the connection:
    client.stop();
  }
}

Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

paul alting

#11
Dave,
Nice to read up on your progress here with the DUE.
Could you edit your last post to place the code within the code tags, it makes it easier to select it all then and is more readable as well.
I would like to take a closer look at it in Eclipse IDE.

With using client.print, can I suggest to try to get as much done in the one statement as you can.
With your code:client.print ("<h2>Midnite Classic </h2>");

          client.println ("<table border=\"1\" cellpadding=\"10\" style=\"width\:70%\"\>");
         
          client.println ("<tr>");         
          client.println ("<td>Name</td>");
          for (k=0; k< CLASSICS; k++ )
          {
             client.print ("<td>");
             client.print (Classic_name[k]);
             client.print (" C");
             client.print (model[k]);
             client.print (" #");
             client.print (serno[k]);     // classic serial number
             client.println("</td>");
          }
          client.println("</tr>");
         
Each client.print sends HTTP data in its own TCP packet, and this makes things slower, less efficient, granted it maybe more readable as source code though.

What you can do is to do something like the following, where all the print data is placed into a char buffer, then you simply send the buffer out directly after connection and headers.
An old example from when I used the Mega with HTTP to send data out.
void postAlarm() {
char postData[210];

sprintf(postData, "{\"data\":[\"alarm\",%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i,%i]}",
vTurbine.minHour, vTurbine.maxHour, vTurbine.minDay, vTurbine.maxDay,                                                                          // 01 02 03 04
iTurbine.minHour, iTurbine.maxHour, iTurbine.minDay, iTurbine.maxDay, iTurbine.totHour, iTurbine.totDay,                            // 05 06 07 08 - 09 10
iSolar.minHour, iSolar.maxHour, iSolar.minDay, iSolar.maxDay, iSolar.totHour, iSolar.totDay,                                                 // 11 12 13 14 - 15 16
vBattery.minHour, vBattery.maxHour, vBattery.minDay, vBattery.maxDay, accum.batteryInDay, accum.batteryOutDay);          // 17 18 19 20 - 21 22

sendData(postData);
}
You can see that you can build up quite long blocks of formatted data using functions like sprintf(..).

Maybe look to calling routines to do this sort of work, then return back to the main loop() with any return error if needed.
And by placing these in a function, any local vars are released, thereby not holding them as global, which is good for large char buffers like above.

Your section:
client.println("HTTP/1.1 200 OK");
          client.println("Content-Type: text/html");
          client.println("Connection: close");  // the connection will be closed after completion of the response
          client.println("Refresh: 5");  // refresh the page automatically every 5 sec
          client.println();
          client.println("<!DOCTYPE HTML>");

          client.println("<html><body>");


Could be sent out in one shot as:
client.println("HTTP/1.1 200 OK\nContent-Type: text/html\nConnection: close\nRefresh: 5\n\n<!DOCTYPE HTML>\n<html><body>");

In case people wish to use EIA-485:
With the DUE, people need to know that the I/O is all 3.3v and any RS-485/RS-232 shield also needs to be 3.3v.
With the Mega, just normal standard 5v devices.

Looking forward to further updates :)
____
Paul
6 x 200W PV into home-brew 6 stage MOSFET charge controller : Microhydro 220Vac 3 phase IMAG
8 x 400Ah LiFeYPO4 Winston : Latronics LS2412 inverter
QuadlogSCADA control and monitoring system : Tasmania, Australia : http://paulalting.com

dgd

#12
Paul,

Thanks for your responses and of course with a formatted print instruction such as sprintf those repetitive prints would not be necessary. Unfortunately the Arduino IDE included C compiler just simply does not support any type of printf instruction.
I know there are some good workarounds suggested in the arduino forums and that I should probably investigate alternates to arduino 1.6.1 IDE but I wanted to keep this code real simple.

Have now installed the tiny web server code so have proper web page server code available with SD card page storage/retrieval support. So next stage is the DUE better web server for up to 4 rs232 connected Classics with daily report listings and some simple stats, analysis etc.
I have also got a bit side tracked looking at the Outback inverter TCP modbus data input as a possibility to include in DUE web server  :) ...but the more I look at the DUE it then becomes clear I should be concentrating on the  Cubie2 as the web server platform  ;)

Dgd


Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand

Westbranch

DGD,  I just did a search for
Quote"Arduino DUE"   "Cubieboard 2"
and there does not seem to be anything out there that is less than ~ 1 yr old...

any suggestions fro comparative articles?
KID FW1811 560W >C&D 24V 900Ah AGM
CL150 29032 FW V.2126-NW2097-GP2133 175A E-Panel WBjr, 3Px4s 140W > 24V 900Ah AGM,
2 Cisco WRT54GL i/c DD-WRT Rtr, NetGr DS104Hub
Cotek ST1500 Inv  want a 24V  ROSIE Inverter
OmniCharge3024  Eu1/2/3000iGens
West Chilcotin 1680+W to come

dgd

Wb,
I could not find anything either, I suppose it's just a matter of comparing specs of both but the main difference, AFAIK, is that the DUE is really an embedded processor system that can be made a limited data processing/web server system, whereas the Cubie is not designed as an embedded system but is more general computer with normal stand alone computer interfaces plus some interesting lower level controller interfaces.
Others probably have different views  :D
Seems almost a waste to limit the Cubie to a black box type system but then it's so low cost  :)

Dgd
Classic 250, 150,  20 140w, 6 250w PVs, 2Kw turbine, MN ac Clipper, Epanel/MNdc, Trace SW3024E (1997), Century 1050Ah 24V FLA (1999). Arduino power monitoring and web server.  Off grid since 4/2000
West Auckland, New Zealand