Here is an example of a drawup I threw together to allow dynamic row updating.

<!DOCTYPE html>
<html>
    <head>
        <script>
            var ClosedCaptioningSocket = new WebSocket("ws://[WANIP]:[WANPORT]/", "protocolOne")
            ClosedCaptioningSocket.onopen = function (event) 
            {
                ClosedCaptioningSocket.send("Here's some text that the server is urgently awaiting!"); 
                document.getElementById("CCDiv").style.display='block';
            };
            ClosedCaptioningSocket.onmessage = function (event) 
            {
                document.getElementById("HTML5CC").innerHTML += event.data;
                document.getElementById("HTML5CC").scrollTop = document.getElementById("HTML5CC").scrollHeight
            }
        </script>
    </head>
<body>
<div id="CCDiv" name="CCDiv" style='display:none';>
<br><br>
Closed Captioning
<br>
    <textarea name="HTML5CC" id="HTML5CC" rows="5" cols="200" readonly="false"></textarea>
</div>
</body>
</html>

Under the hood to send the data using .NET, Create a socket and send out data once connected to something like this.

Public Sub SendData(Data As String)
        Dim Stream As NetworkStream = _TcpClient.GetStream()
        Dim DataToSend As Byte() = System.Text.Encoding.UTF8.GetBytes(Data)
        Dim FRRROPCODE As Byte = Convert.ToByte("10000001", 2) 'FIN is set, and OPCODE is 1 or Text
        Dim header As Byte() = {FRRROPCODE, Convert.ToByte(DataToSend.Length)}


        Dim ResponseData As Byte()
        ReDim ResponseData((header.Length + DataToSend.Length) - 1)
        'NOTEWORTHY: if you Redim ResponseData(header.length + Payload.Length).. you'll add a 0 value byte at the end of the response data.. 
        'which tells the client that your next stream write will be a continuation frame..

        Dim index As Integer = 0

        Buffer.BlockCopy(header, 0, ResponseData, index, header.Length)
        index += header.Length

        Buffer.BlockCopy(DataToSend, 0, ResponseData, index, DataToSend.Length)
        index += DataToSend.Length
        Stream.Write(ResponseData, 0, ResponseData.Length)
    End Sub

So this weekend, I ended up overhauling my ESP8266 DHT library to make it plug and play into other projects. One big thing to take aware from this is that GPIO 15 is off limits due to the pin being required to be low / grounded during boot or it will not leverage SPI to start up.
Also GPIO16 is also off limits as well for GPIO toggling, With this being said 6-11 is also offlimits for SPI. So what’s left? Not much, I’m testing with GPIO13 at the moment to see if it can handle the data line floating while the esp is rebooting.

//https://www.mikrocontroller.net/attachment/263828/The-ESP8266-Book-August-2015.pdf
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "ip_addr.h"
#include "mem.h"
#include "user_interface.h"
#include "lwip/stats.h"
#include "espconn.h"

#include "c_types.h" ////ONE WIRE

#include "../library/uart.h" //Copy these from your Driver Lib to your local folder
#include "../library/gpio16.h" //Copy these from your Driver Lib to your local folder

#include "../library/common.h"
#include "../library/dht.h"
#include "../library/station.h"
#include "../library/sockets.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#define user_procTaskPrio        0
#define user_procTaskQueueLen    1
os_event_t user_procTaskQueue[user_procTaskQueueLen];

void ICACHE_FLASH_ATTR StationConnected()
{
os_printf("[%s]\r\n", __func__);
os_printf("Socket function Temp =  %d *F, Hum = %d %%\n", (int)(GlobalReading.temperature * 1.8 + 32), (int)(GlobalReading.humidity));
init_sockets(NULL, NULL, NULL, NULL); //Do not override Socket.H callbacks

//Creates Timer Socket
uint8 FreeSocket = GetFreeSocket();
if (FreeSocket == 255)
{
os_printf("No Free socket avilable\r\n");
return;
}
os_strcpy(MySendDataStruct[FreeSocket].Name, "MyThermSocket");
MySendDataStruct[FreeSocket].Domain = DOMAIN;
os_sprintf(MySendDataStruct[FreeSocket].DataToSend, "GET /MyEsp.php?ssid=myssid&IP=MyIp2&ID=MyId2&temp=%d&hum=%d HTTP/1.1\r\nUser-Agent: SomeAgent\r\nHost: %s\r\nAccept: */*\r\n\r\n", (int)(GlobalReading.temperature * 1.8 + 32), (int)(GlobalReading.humidity), DOMAIN);
StartSendingSocketTimer(FreeSocket);
}

void ICACHE_FLASH_ATTR myDHTFunctionCallback(struct sensor_GlobalReading * MyReading)
{
os_printf("[%s]\r\n", __func__);
os_printf("Callback function Temp =  %d *F, Hum = %d %%\n", (int)(GlobalReading.temperature * 1.8 + 32), (int)(GlobalReading.humidity));
init_station("Thermastat.local", true, &StationConnected); //Connect to stronegest open AP
}

void ICACHE_FLASH_ATTR sdk_init_done_cb(void) 
{ 
os_printf("[%s] initializing ESP8266!\r\n", __func__);

SpiFlashOpResult ReadResult = spi_flash_read(ThermMemorySpace,(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));

if (ReadResult != SPI_FLASH_RESULT_OK || ThermostatConfig.programmed != 1 || true) //If not set, Set it..
{
os_printf("Setting's not found, Calling Set_ThermostatSettings\r\n");
//NOTE: Don't use GPIO16/D0, This is reserved.
//DHT22 GPIO=GPIO0/D3 Power=GPIO15/D8 PollingEnabled Interval=5Min SendOnInit=true SendIfOnlyIf=false tempatureDegrees=40 classification="warmer" DeepSleepAfterSend DeepSleepTime Enabled Reserved
//SpiFlashOpResult writeResult = Set_ThermostatSettings(MySensor_DHT22, 0, 15, true, 5, true, false, 40, "warmer", false, NULL, true, NULL);
//DHT22 Data=GPIO15/D8 Power=GPI13/D7 PollingEnabled Interval=5Min SendOnInit=true SendIfOnlyIf=false tempatureDegrees=40 classification="warmer" DeepSleepAfterSend DeepSleepTime Enabled Reserved
SpiFlashOpResult writeResult = Set_ThermostatSettings(MySensor_DHT22, 13, 15, true, 5, true, false, 40, "warmer", false, NULL, true, NULL);
//DHT22 GPIO=GPIO0/D3 Power=GPIO4/D2 PollingEnabled Interval=1Min SendOnInit=true SendIfOnlyIf=false tempatureDegrees=NULL classification=warmer/colder DeepSleepAfterSend DeepSleepTime Enabled Reserved
//Set_ThermostatSettings(MySensor_DHT22, 0, 4, true, 1, true, false, NULL, "warmer", false, 5, true, NULL);
if (writeResult == SPI_FLASH_RESULT_OK)
{
init_ThermostatSettings(&myDHTFunctionCallback);
}
}
else
{
init_ThermostatSettings(&myDHTFunctionCallback);
}
}

void ICACHE_FLASH_ATTR user_init()
{
//void  uart0_tx_buffer(uint8 *buf,
uint16 len)
uart_div_modify(0, UART_CLK_FREQ / 115200);
wifi_set_opmode(0);
wifi_set_sleep_type( NONE_SLEEP_T );

ETS_GPIO_INTR_DISABLE();// Disable gpio interrupts
gpio_init();

//Start os task
system_init_done_cb(sdk_init_done_cb);
//system_os_task(loop, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen); //Task to Signal for later
}

So today I ran into a little bit of a snag, I was trying to copy an unknown amount of data into a buffer and then strcat That into another buffer. However during this I had a slight issue where the unknown data coming in the first buffer even though it fits into the destination buffer once it gets strcat into the 2nd buffer it may not. So I had identify the size of the unknown data, the issue was that I was pulling this data during runtime via SPIflash so I crafted this nice little function below to give me an idea of the size of the data that is in the 2nd buffer then in my main function count down the remaining bytes as I take the data in to the first unknown buffer, then chopping off the rest to prevent the chip from crashing in a buffer overflow.

uint16 StrLenFlash(uint32_t address, char * Terminator)
{
    int i = 0;
    int index = 0;
    int sizeofTerminator = os_strlen(Terminator);
    char buffer[4];
    uint16 addressindex = 0;
    while(true)
    {
        system_soft_wdt_feed();
        if (spi_flash_read(address+(addressindex*4), buffer, 4) != 0)
        {
            os_printf("Read failed at offset=0x%02x index=%d\r\n", address, index);
            return 0;
        }
        addressindex++;
        for (i=0; i<=3; i++)
        {
            if (buffer[i] == *(Terminator+index))
            {
                //os_printf("Found match %c | %c\r\n", buffer[i], *(Terminator+index));
                index++;
            }
            else
            {
                index = 0;
            }
            if (index == sizeofTerminator)
            {
                //os_printf("EOF Found");
                return addressindex*4;
            }
        }
    }
}

So after hunting around for a little bit, I stumbled upon these as a solution.

http://www.ti.com/lit/ds/symlink/lm3671.pdf

The device seemed very efficient and a perfect solution for a 3.7V Lipo to Power a 3.3V ESP and DHT11/22 Thermostat. One thing to note is this also has an EN pin, I may need to jump it to the VIN to ensure this is alway’s enabled on for my device. Seem that after taking a look at the Typical Application sch that implementing one of these on a Prototype board won’t be too bad. I’ll need to hook it up to my home power supply to test the voltage drop and see if It can hang in at 3.3volts even while the Lipo is on its last legs at the end of the battery drain.

So Lucky for me Adafruit has a small little PCB with this installed on it with a few header pins. One of the gotchas though is that for this project and as normal we need to make a Ground rail so that everything can connect to common. Now one thing to take from this is that the breakout board seems to have a Surface Mount Device/Technology resistor attached to the feedback line. This resister is E24 marked resistor. To calculate the value take the first two digits and then add the third digit amount of zeros. In this case 104 turn’s into “10” + “0000” = 100,000 or it’s a 100kohm resistor.

So recently I just finished Arabesque Opus. 100 No. 2 by Burgmuller. The song looked difficult at first but turned out to be actually pretty easy. First: By taking a look at the last chord we can easily identify that the song is written in A Minor. Second: The speed is fast pace using a 2/4 key signature.

The song starts with A minor triad on the left hand to start the beat of the tempo. This is something to note as sometimes you can go to fast on your left and your right has to go twice as fast to keep up, So it’s best to take this beat as slow as possible without messing up your timing. Next, it goes from A Minor to D/F then back to A. A Melody is built then it ends on a ‘E’ sforzando! Nice and loud.

The phrase repeats then goes into a fast pace left hand progression just like the right. Then is almost mirrored at the starts with an A to a D/F back to an A.

One big thing to note are the repeat bars to ensure you revert back to the correct bar to continue playing again.

and lastly ending on SF Fermata of A. Fermata has a long emphasis, so be aware.

A great list of symbol definition can be found here. https://melodyful.com/complete-list-of-music-symbols-with-their-meaning

So, In the last few weeks’s I have been converting my Large ESP8266 project to multiple .h Module files so I can carry functions over from project to project and at the same time have them centrally managed to update code / fix bugs so they carry over to all of my projects.

One important detail on how I do this is to be able to trigger function code from within the Main project as needed so I don’t have to handle user specific events within the Header file where it does not belong. So, I do this by using TypeDef and declaring a Prototype for my Callback function. In this case,

typedef void (*DHTFunctionCallback)(struct sensor_GlobalReading * MyReading);
DHTFunctionCallback DHTCallBack;

Then set the callback function,

init_ThermostatSettings(&myDHTFunctionCallback);

Set the callback in the Header file

void ICACHE_FLASH_ATTR init_ThermostatSettings(void * LDHTCallBack(struct sensor_GlobalReading MyReading))
{
if (LDHTCallBack != NULL)
{
    DHTCallBack = LDHTCallBack;
}
}

Then in my Header file I then check to see if the value is set != NULL. If so then I call it.

DHTCallBack(&GlobalReading);

The Main Function will get triggered and I can then access the variables stored in the STACK/HEAP depending on how I pass it to the caller from the callee.

void ICACHE_FLASH_ATTR myDHTFunctionCallback(struct sensor_GlobalReading * MyReading)
{
    os_printf("[%s]\r\n", __func__);
}

One thing to note for the LOVE OF ORANGE JUICE WATCH OUT FOR USE AFTER FREE ISSUES. If your doing this from an ASync call just be aware to Lock the thread/variables so you don’t crash or use Data that get’s falsely injected!

With this method you can just Include the Handler, Call the Coordinating Init Function and pass the &Address of a function matching the prototype and your off to the races!

Full Header and Main.C example
DHT.H
#ifndef dhtthermastat
#define dhtthermastat

#include "../library/common.h"
#include "../library/station.h"
#define ThermMemorySpaceSector 0x50
#define ThermMemorySpace 0x50000
#define DHT_MAXCOUNT 32000
#define DHT_NO_PIN -1
#define DHT_PACKET_SIZE 5

///NOTE: The call back points to a Global Structure named GlobalReading, This structure can / may change by the time user code executes. It may be best to copy the variable staticly.

typedef void (*DHTFunctionCallback)(struct sensor_GlobalReading * MyReading);
DHTFunctionCallback DHTCallBack;

int DHT_PIN = 0;

LOCAL struct espconn TCPOutGoingespconn; //This sends outgoing get request
static volatile os_timer_t CheckIPAndSend_timer;

enum sensor_type MySensor;
enum sensor_type
{
    MySensor_DHT11,MySensor_DHT22
};

struct __attribute__((__packed__)) ThermostatStruct{
    int programmed;
    enum sensor_type ThermostatType;
    int GPIO;
    int PowerMethod;
    BOOL PollingEnabled;
    int Polling;
    BOOL SendOnInit;
    BOOL SendOnInitOnlyIf;
    int tempatureDegrees;
    BOOL classification;
    BOOL DeepSleepAfterSend;
    int DeepSleepTime;
    BOOL Enabled;
    char Reserved[14]; //This fixes the 4 Byte Allignment in SPI Flash Read, 44bytes
};

struct ThermostatStruct ThermostatConfig;

struct sensor_GlobalReading{
    float temperature;
    float humidity;
    const char* source;
    uint8_t sensor_id[16];
    BOOL success;
};


void ICACHE_FLASH_ATTR DHT(void);
//struct sensor_GlobalReading * ICACHE_FLASH_ATTR readDHT(int force);
void DHTInit(enum sensor_type LMySensor, uint32_t GPIOPin, bool enablepolling, uint32_t polltime);

static inline float scale_humidity(int *data) {
  if (MySensor == MySensor_DHT11) {
    return data[0];
  } else {
    float humidity = data[0] * 256 + data[1];
    return humidity /= 10;
  }
}

static inline float scale_temperature(int *data) 
{
    if (MySensor == MySensor_DHT11) 
    {
        os_printf("MySensor DHT11");
        return data[2];
    } 
    else 
    {
        os_printf("MySensor DHT22");
        float temperature = data[2] & 0x7f;
        temperature *= 256;
        temperature += data[3];
        temperature /= 10;
        if (data[2] & 0x80)
        temperature *= -1;
        return temperature;
    }
}

struct sensor_GlobalReading GlobalReading = {
    .source = "DHT11", .success = 0
};

void ICACHE_FLASH_ATTR renderHTTPThermostatrequest(char * Request)
{
    decodeHTML(Request);
    if (os_strlen(Request) > 127)
    {
        os_printf("Returning - GET VAR IS TOO BIG: %s\r\n", Request);
        return;
    }

    char HTTPGETSPLIT[128];
    os_memset(HTTPGETSPLIT, 0, 128);
    os_memcpy(&HTTPGETSPLIT, Request, os_strlen(Request));
    os_printf("Before Split: %s\r\n", HTTPGETSPLIT);
    char * Key = strstr(HTTPGETSPLIT, "=");
    if(Key == NULL)
    {
        os_printf("Returning - Not a valid Split: %s\r\n", HTTPGETSPLIT);
        return;
    }
    *Key = 0x0;
    char * Value = Key + 1;
    Key = HTTPGETSPLIT;

    os_printf("Key: %s\r\nValue: %s\r\n", Key, Value);

    os_printf("renderHTTPThermostatrequest Key: %s\r\nValue: %s\r\n", Key, Value);
    if (strcmp(Key, "Thermostat") == 0)
    {
        //os_strcpy(newconfig.ssid, Value);
        if (strcmp(Value, "DHT11") == 0)
        {
            os_printf("Setting to DHT11");
            ThermostatConfig.ThermostatType = MySensor_DHT11;
        }
        else
        {
            os_printf("Setting to DHT22");
            ThermostatConfig.ThermostatType = MySensor_DHT22;
        }
        os_printf("Thermastat Set to: ", Value);
        return;
    }
    else if (strcmp(Key, "GPIO") == 0)
    {
        ThermostatConfig.GPIO = atoi(Value);
        os_printf("GPIO set to %s - %d", Value, atoi(Value));
    }
    else if (strcmp(Key, "PowerMethod") == 0)
    {
        ThermostatConfig.PowerMethod = atoi(Value);
    }
    else if (strcmp(Key, "pollingEnabled") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.PollingEnabled = true;
        }
        else
        {
            ThermostatConfig.PollingEnabled = false;
        }
    }
    else if (strcmp(Key, "POLLING") == 0)
    {
        ThermostatConfig.Polling = atoi(Value);
        os_printf("Polling set to %s - %d", Value, atoi(Value));
    }
    else if (strcmp(Key, "SendOnInit") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.SendOnInit = true;
        }
        else
        {
            ThermostatConfig.SendOnInit = false;
        }
    }
    else if (strcmp(Key, "SendOnInitOnlyIf") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.SendOnInitOnlyIf = true;
        }
        else
        {
            ThermostatConfig.SendOnInitOnlyIf = false;
        }
    }
    else if (strcmp(Key, "tempatureDegrees") == 0)
    {
        ThermostatConfig.tempatureDegrees = atoi(Value);
    }
    else if (strcmp(Key, "classification") == 0)
    {
        if (strcmp(Value, "warmer") == 0)
        {
            ThermostatConfig.classification = true;
        }
        else if (strcmp(Value, "colder") == 0)
        {
            ThermostatConfig.classification = false;
        }
    }
    else if (strcmp(Key, "DeepSleepAfterPoll") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.DeepSleepAfterSend = true;
        }
        else if (strcmp(Value, "false") == 0)
        {
            ThermostatConfig.DeepSleepAfterSend = false;
        }
    }
    else if (strcmp(Key, "DeepSleepTime") == 0)
    {
        ThermostatConfig.DeepSleepTime = atoi(Value);
    }
    else if (strcmp(Key, "enabled") == 0)
    {
        if (strcmp(Value, "true") == 0)
        {
            ThermostatConfig.Enabled = true;
        }
        else
        {
            ThermostatConfig.Enabled = false;
        }

        //os_printf("ssid: \"%s\"\npw: \"%s\"\nProgrammed: %d\r\n",newconfig.ssid,newconfig.password,newconfig.programmed);
        ThermostatConfig.programmed = 1;
        //os_printf("Writing ThermConfig at %02x\r\n", (WifiMemorySpace+sizeof(APFlashStationConf)+sizeof(newconfig)));
        spi_flash_erase_sector(ThermMemorySpaceSector);
        SpiFlashOpResult writeResult = spi_flash_write(ThermMemorySpace, (uint32 *)&ThermostatConfig, sizeof(ThermostatConfig));
        if (writeResult == SPI_FLASH_RESULT_OK)
        {
            /*
            ThermostatConfig.programmed = 0;
            SpiFlashOpResult ReadResult = spi_flash_read(0x50000,(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));     
            if (ReadResult == SPI_FLASH_RESULT_OK)
            {
                os_printf("Therm SPI Read SPI_FLASH_RESULT_OK\r\n");
                if(ThermostatConfig.programmed == 1)
                {
                    os_printf("\r\nSaved ThermostatConfig Information Found!!\r\nThermostatType: \"%d\"\nGPIO: \"%d\"\r\n", ThermostatConfig.ThermostatType, ThermostatConfig.GPIO);
                    if(ThermostatConfig.Enabled == true)
                    {
                        os_printf("Thermostat Enabled - Starting Polling at %d\r\n", ThermostatConfig.Polling);
                        DHTInit(MySensor_DHT11, ThermostatConfig.PollingEnabled, ThermostatConfig.Polling * 1000); //1000 = 1 Sec
                    }
                }
            }
            */

            os_printf("ThermSettings SavedSystem is rebooting...");     
            //os_delay_us(100000);
            os_printf("now...");        
            system_restart();
        }
        else if(writeResult == SPI_FLASH_RESULT_ERR)
        {
            os_printf("ThermSettings SPI_FLASH_RESULT_ERR...");
        }
        else if(writeResult == SPI_FLASH_RESULT_TIMEOUT)
        {
            os_printf("ThermSettings SPI_FLASH_RESULT_TIMEOUT...");
        }
        return;

    }
    else /* default: */
    {
        os_printf("No valid request Handler for - %s\r\n", Request); //Output last variable
        /*
        int i;
        for(i = 0; i < 10; i++) {
                os_printf("0x%02X ", Request[i]);
        }
        */
    }
}

LOCAL bool ICACHE_FLASH_ATTR pollDHTCb()
{
    //Something is going on with Powermethod on GPIO15?
    os_printf("pollDHTCb()");
    if (ThermostatConfig.PowerMethod > 0)
    {
        os_printf("Turning on power to the DHT - Pin%d\r\n", ThermostatConfig.PowerMethod);
        PIN_FUNC_SELECT(g_pin_muxes[ThermostatConfig.PowerMethod], g_pin_funcs[ThermostatConfig.PowerMethod]);
        gpio_output_set((1 << ThermostatConfig.PowerMethod), 0, 0, 0); //Turn on power to the DHT
    }
    if(ThermostatConfig.programmed != 1)
    {
        os_printf("pollDHTCb, not programmed\r\n");
        return false;
    }
    int counter = 0;
    int laststate = 1;
    int i = 0;
    int bits_in = 0;
    int data[100];
    data[0] = data[1] = data[2] = data[3] = data[4] = 0;
    //disable interrupts, start of critical section
    //os_intr_lock();
    wdt_feed();
    // Wake up device, 250ms of high
    GPIO_OUTPUT_SET(DHT_PIN, 1);
    delay_ms(250);
    // Hold low for 20ms
    GPIO_OUTPUT_SET(DHT_PIN, 0);
    delay_ms(20);
    // High for 40us
    GPIO_OUTPUT_SET(DHT_PIN, 1);
    os_delay_us(40);
    GPIO_DIS_OUTPUT(DHT_PIN);
    i=0;
    while (GPIO_INPUT_GET(DHT_PIN) == 1) 
    {
        os_delay_us(3);
        if (i >= DHT_MAXCOUNT) 
        {
            goto fail;
        }
        i++;
    }
    i=0;
    while (GPIO_INPUT_GET(DHT_PIN) == 0) 
    {
        os_delay_us(3);
        if (i >= DHT_MAXCOUNT) 
        {
            goto fail;
        }
        i++;
    }

    counter = 0;
    while (counter < 40)
    {
        i=0;
        while (GPIO_INPUT_GET(DHT_PIN) == 1) 
        {
            os_delay_us(3);
            if (i >= DHT_MAXCOUNT) 
            {
                goto fail;
            }
            i++;
        }

        i=0;
        while (GPIO_INPUT_GET(DHT_PIN) == 0) 
        {
            os_delay_us(3);
            if (i >= DHT_MAXCOUNT) 
            {
                goto fail;
            }
            i++;
        }

        os_delay_us(47);
        data[bits_in / 8] <<= 1;
        if (GPIO_INPUT_GET(DHT_PIN) == 1)
        {
            data[bits_in / 8] |= 1;
            //os_printf("\r\nONE %d", counter);
        }
        else
        {
            //os_printf("\r\nZERO %d", counter);
        }
        bits_in++;
        counter++;
    }

    //Re-enable interrupts, end of critical section
    //os_intr_unlock();
    if (ThermostatConfig.PowerMethod > 0)
    {
        os_printf("Turning off power to DHT\r\n");
        gpio_output_set(0, (1 << ThermostatConfig.PowerMethod), 0, 0); //Turn off power to the DHT
    }

    if (bits_in < 40) {
        os_printf("Got too few bits: %d should be at least 40\r\n", bits_in);
        goto fail;
    }


    int checksum = (data[0] + data[1] + data[2] + data[3]) & 0xFF;

    //os_printf("DHT: %02x %02x %02x %02x [%02x] CS: %02x", data[0], data[1],data[2],data[3],data[4],checksum);

    if (data[4] != checksum) 
    {
        os_printf("Checksum was incorrect after %d bits. Expected %d but got %d\r\n", bits_in, data[4], checksum);
        goto fail;
    }

    GlobalReading.temperature = scale_temperature(data);
    GlobalReading.humidity = scale_humidity(data);
    os_printf("Temp =  %d *F, Hum = %d %%\n", (int)(GlobalReading.temperature * 1.8 + 32), (int)(GlobalReading.humidity));
    GlobalReading.success = 1;
    DHTCallBack(&GlobalReading); //Invoke Callback
    return true;

    fail:
        os_printf("Failed to get GlobalReading, dying\n");
        GlobalReading.success = 0;
        if (ThermostatConfig.PowerMethod > 0)
        {
            os_printf("Turning off power to DHT\r\n");
            gpio_output_set(0, (1 << ThermostatConfig.PowerMethod), 0, 0); //Turn off power to the DHT
        }
        return false;
}

LOCAL bool ICACHE_FLASH_ATTR pollDHT()
{
    if(ThermostatConfig.programmed != 1)
    {
        os_printf("Polling DHT, not programmed\r\n");
        return false;
    }
    os_printf("Polling DHT\r\n");
    if (pollDHTCb())  //Get Tempature from DHT
    {
        int TempInF = (int)(GlobalReading.temperature * 1.8 + 32);
        if (ThermostatConfig.SendOnInitOnlyIf)
        {
            if(ThermostatConfig.classification)
            {
                if (TempInF > ThermostatConfig.tempatureDegrees) //Warmer
                {
                    os_printf("Warmer: TempInF > ThermostatConfig.tempatureDegrees\r\n");
                    //Turn On LED
                    DHTCallBack(&GlobalReading);
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set(0, (1 << 2), 0, 0);
                }
                else
                {
                    //Turn OFF LED
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set((1 << 2), 0, 0, 0);
                }
            }
            else if(ThermostatConfig.classification) //Colder
            {
                if (TempInF < ThermostatConfig.tempatureDegrees)
                {
                    os_printf("Colder: TempInF < ThermostatConfig.tempatureDegrees\r\n");
                    //Turn On LED
                    DHTCallBack(&GlobalReading);
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set(0, (1 << 2), 0, 0);
                }
                else
                {
                    //Turn OFF LED
                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                    gpio_output_set((1 << 2), 0, 0, 0);
                }
            }
        }
        else
        {
            os_printf("Sending on Poll\r\n");
        }
    }
}

void DHTInit(enum sensor_type LMySensor, uint32_t GPIOPin, bool enablepolling, uint32_t polltime) 
{
    os_printf("[%s]\r\n", __func__);
    MySensor = LMySensor;
    //PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO0_U, FUNC_GPIO0);
    //PIN_PULLUP_EN(PERIPHS_IO_MUX_GPIO0_U);
    PIN_FUNC_SELECT(g_pin_muxes[GPIOPin], g_pin_funcs[GPIOPin]);
    PIN_PULLUP_EN(g_pin_muxes[GPIOPin]);
    DHT_PIN = GPIOPin;
    if (enablepolling)
    {
        os_printf("DHT Setup for type %d, poll interval of %d using GPIO %d, Starting Timer...\r\n", LMySensor, (int)polltime, GPIOPin);
        static ETSTimer dhtTimer;
        os_timer_setfn(&dhtTimer, pollDHT, NULL);
        os_timer_arm(&dhtTimer, polltime, 1);
    }
    else
    {
        os_printf("DHT Setup for type %d using GPIO %d\n", LMySensor, GPIOPin);
    }

}


char * DOMAIN = "controllingTheInter.net";
bool sentAlert=false;

//char requestText[128];
//  int TempInF = (int)(GlobalReading.temperature * 1.8 + 32);
//  int humidity = (int)GlobalReading.humidity;
//  os_sprintf(requestText,"GET /esp8266.php?ssid=myssid&IP=MyIp&ID=MyId /HTTP/1.1\r\nUser-Agent: F%dH%d\r\nHost: %s\r\nAccept: */*\r\n\r\n", TempInF, humidity, DOMAIN);
//  os_printf("Sending: %s", requestText);
//  espconn_send(conn,requestText,128);
//  sentAlert=true;

//Add code to support new sockets sending data.
void ICACHE_FLASH_ATTR LoadStationAndSendData(struct sensor_GlobalReading MyReading)
{
    init_station(NULL, NULL, NULL);     
    //LoadAccessPoint();
    //os_timer_setfn(&CheckIPAndSend_timer, (os_timer_func_t *)network_check_ip_send_therm, (void *)&MyReading);
    //os_timer_arm(&CheckIPAndSend_timer, 1000, 1);
}

SpiFlashOpResult ICACHE_FLASH_ATTR Set_ThermostatSettings(enum sensor_type LThermostatType, int LGPIO, int LPowerMethod, bool LPollingEnabled, int LPolling, bool LSendOnInit, bool LSendOnInitOnlyIf, int LtempatureDegrees, char * LClassification, bool LDeepSleepAfterSend, int LDeepSleepTime, int LEnabled, char * LReserved)
{
    os_printf("[%s]\r\n", __func__);
    ThermostatConfig.ThermostatType = LThermostatType;
    DHT_PIN = LGPIO;
    ThermostatConfig.GPIO = LGPIO;
    ThermostatConfig.PowerMethod = LPowerMethod;
    ThermostatConfig.PollingEnabled = LPollingEnabled;
    ThermostatConfig.Polling = LPolling;
    ThermostatConfig.SendOnInit = LSendOnInit;
    ThermostatConfig.SendOnInitOnlyIf = LSendOnInitOnlyIf;
    ThermostatConfig.tempatureDegrees = LtempatureDegrees;
    if (LClassification != NULL)
    {
        if (strcmp(LClassification, "warmer") == 0)
        {
            ThermostatConfig.classification = true;
        }
        else if (strcmp(LClassification, "colder") == 0)
        {
            ThermostatConfig.classification = false;
        }
    }
    ThermostatConfig.DeepSleepAfterSend = LDeepSleepAfterSend;
    ThermostatConfig.DeepSleepTime = LDeepSleepTime;
    ThermostatConfig.Enabled = LEnabled;
    ThermostatConfig.programmed = 1;
    //os_printf("Writing ThermConfig at %02x\r\n", (WifiMemorySpace+sizeof(APFlashStationConf)+sizeof(newconfig)));
    spi_flash_erase_sector(ThermMemorySpaceSector);
    SpiFlashOpResult writeResult = spi_flash_write(ThermMemorySpace, (uint32 *)&ThermostatConfig, sizeof(ThermostatConfig));
    if (writeResult == SPI_FLASH_RESULT_OK)
    {
        //os_printf("ThermSettings SavedSystem is rebooting...");       
        //os_delay_us(100000);
        //os_printf("now...");      
        //system_restart();
    }
    else if(writeResult == SPI_FLASH_RESULT_ERR)
    {
        os_printf("ThermSettings SPI_FLASH_RESULT_ERR...");
    }
    else if(writeResult == SPI_FLASH_RESULT_TIMEOUT)
    {
        os_printf("ThermSettings SPI_FLASH_RESULT_TIMEOUT...");
    }
    return writeResult;
}

void ICACHE_FLASH_ATTR init_ThermostatSettings(void * LDHTCallBack(struct sensor_GlobalReading MyReading))
{
    os_printf("[%s]\r\n", __func__);
    //os_printf("GlobalReading ThermConfig at %02x\r\n", (WifiMemorySpace+sizeof(FlashStationConf)+sizeof(APFlashStationConf)));
    //SpiFlashOpResult ReadResult = spi_flash_read(WifiMemorySpace+sizeof(FlashStationConf)+sizeof(APFlashStationConf),(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));
    SpiFlashOpResult ReadResult = spi_flash_read(ThermMemorySpace,(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));        
    if (ReadResult == SPI_FLASH_RESULT_OK)
    {
        os_printf("Therm SPI Read SPI_FLASH_RESULT_OK\r\n");
        if(ThermostatConfig.programmed == 1)
        {
            os_printf("Saved ThermostatConfig Information Found!!\r\nThermostatType: \"%d\"\nGPIO: \"%d\"\r\nTempature: \"%d\"\r\n", ThermostatConfig.ThermostatType, ThermostatConfig.GPIO, ThermostatConfig.tempatureDegrees);
            if(ThermostatConfig.Enabled == true)
            {
                if (LDHTCallBack != NULL)
                {
                    DHTCallBack = LDHTCallBack;
                }
                os_printf("Thermostat Enabled - Starting Polling at %d\r\n", ThermostatConfig.Polling);
                DHTInit(ThermostatConfig.ThermostatType, ThermostatConfig.GPIO, ThermostatConfig.PollingEnabled, ThermostatConfig.Polling * 1000 * 60); //1000 = 1 Sec

                if (ThermostatConfig.SendOnInit)
                {
                    if (pollDHTCb()) //This gets the raw value
                    {//This part may be able to be turned into a function
                        int TempInF = (int)(GlobalReading.temperature * 1.8 + 32);
                        if (ThermostatConfig.SendOnInitOnlyIf)
                        {
                            if(ThermostatConfig.classification)
                            {
                                if (TempInF > ThermostatConfig.tempatureDegrees) //Warmer
                                {
                                    os_printf("Warmer: TempInF > ThermostatConfig.tempatureDegrees\r\n");
                                    //wifi_set_opmode(STATION_MODE);
                                    //LoadStation();
                                    DHTCallBack(&GlobalReading);
                                    //Turn On LED
                                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                                    gpio_output_set(0, (1 << 2), 0, 0);
                                }
                            }
                            else if(ThermostatConfig.classification) //Colder
                            {
                                if (TempInF < ThermostatConfig.tempatureDegrees)
                                {
                                    os_printf("Colder: TempInF < ThermostatConfig.tempatureDegrees\r\n");
                                    DHTCallBack(&GlobalReading);
                                    //Turn On LED
                                    PIN_FUNC_SELECT(PERIPHS_IO_MUX_GPIO2_U, FUNC_GPIO2);
                                    gpio_output_set(0, (1 << 2), 0, 0);
                                    //wifi_set_opmode(STATION_MODE);
                                    //LoadStation();    
                                }
                            }
                        }
                        else
                        {
                            //wifi_set_opmode(STATION_MODE);
                            //LoadStation();
                        }
                        if(ThermostatConfig.DeepSleepAfterSend && false)
                        {
                                //SET_PERI_REG_MASK(UART_CONF0(0),  UART_TXFIFO_RST);//RESET    FIFO
                                //CLEAR_PERI_REG_MASK(UART_CONF0(0),    UART_TXFIFO_RST);
                                os_printf("Going to sleep for %d\r\n", ThermostatConfig.DeepSleepTime);
                                deep_sleep_set_option(2);
                                system_deep_sleep(ThermostatConfig.DeepSleepTime * 60000 * 1000); //UC to Minutes
                        }
                    }
                }
            }
        }
        else
        {
            os_printf("\r\nNo ThermostatConfig Information Found!!\r\n");
        }
    }
    else if(ReadResult == SPI_FLASH_RESULT_ERR)
    {
        os_printf("SPI_FLASH_RESULT_ERR");
    }
    else if(ReadResult == SPI_FLASH_RESULT_TIMEOUT)
    {
        os_printf("SPI_FLASH_RESULT_TIMEOUT");
    }

    //os_printf("SizeOf(ThermostatConfig) = %d\r\n", sizeof(ThermostatConfig));
}
#endif

Main.C

//https://www.mikrocontroller.net/attachment/263828/The-ESP8266-Book-August-2015.pdf
#include "ets_sys.h"
#include "osapi.h"
#include "gpio.h"
#include "os_type.h"
#include "ip_addr.h"
#include "mem.h"
#include "user_interface.h"
#include "lwip/stats.h"
#include "espconn.h"

#include "c_types.h" ////ONE WIRE

#include "../library/uart.h" //Copy these from your Driver Lib to your local folder
#include "../library/gpio16.h" //Copy these from your Driver Lib to your local folder

#include "../library/common.h"
#include "../library/dht.h"
#include "../library/station.h"
#include "../library/sockets.h"
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

#define user_procTaskPrio        0
#define user_procTaskQueueLen    1
os_event_t user_procTaskQueue[user_procTaskQueueLen];

void ICACHE_FLASH_ATTR StationConnected()
{
    os_printf("[%s]\r\n", __func__);
    //Creates Timer Socket
    uint8 FreeSocket = GetFreeSocket();
    os_strcpy(MySendDataStruct[FreeSocket].Name, "MyThermSocket");
    MySendDataStruct[FreeSocket].Domain = DOMAIN;
    os_sprintf(MySendDataStruct[FreeSocket].DataToSend, "GET /esp8266.php?ssid=myssid&IP=MyIp2&ID=MyId2 /HTTP/1.1\r\nUser-Agent: SomeAgent\r\nHost: %s\r\nAccept: */*\r\n\r\n", MySendDataStruct[FreeSocket].Domain);
    StartSendingSocketTimer(FreeSocket);
}

void ICACHE_FLASH_ATTR myDHTFunctionCallback(struct sensor_GlobalReading * MyReading)
{
    os_printf("[%s]\r\n", __func__);
    //init_station("Thermastat.local", true, &StationConnected);
    //init_sockets(NULL, NULL, NULL, NULL); //Do not override Socket.H callbacks
}

void ICACHE_FLASH_ATTR sdk_init_done_cb(void) 
{ 
    os_printf("[%s] initializing ESP8266!\r\n", __func__);

    SpiFlashOpResult ReadResult = spi_flash_read(ThermMemorySpace,(uint32 *)&ThermostatConfig,sizeof(ThermostatConfig));        
    if (ReadResult != SPI_FLASH_RESULT_OK || ThermostatConfig.programmed != 1 || true) //If not set, Set it..
    {
        os_printf("Setting's not found, Calling Set_ThermostatSettings");
        //NOTE: Don't use GPIO16/D0, This is reserved.
        //DHT22 GPIO=GPIO0/D3 Power=GPIO15/D8 PollingEnabled Interval=1Min SendOnInit=true SendIfOnlyIf=false tempatureDegrees=NULL classification DeepSleepAfterSend DeepSleepTime Enabled Reserved
        SpiFlashOpResult writeResult = Set_ThermostatSettings(MySensor_DHT22, 0, 15, true, 1, true, false, NULL, NULL, false, NULL, true, NULL);
        //DHT22 GPIO=GPIO0/D3 Power=GPIO4/D2 PollingEnabled Interval=1Min SendOnInit=true SendIfOnlyIf=false tempatureDegrees=NULL classification=warmer/colder DeepSleepAfterSend DeepSleepTime Enabled Reserved
        //Set_ThermostatSettings(MySensor_DHT22, 0, 4, true, 1, true, false, NULL, "warmer", false, 5, true, NULL);
        if (writeResult == SPI_FLASH_RESULT_OK)
        {
            init_ThermostatSettings(&myDHTFunctionCallback);
        }
    }
    else
    {
        init_ThermostatSettings(&myDHTFunctionCallback);
    }

}

void ICACHE_FLASH_ATTR user_init()
{

    //void  uart0_tx_buffer(uint8   *buf,   uint16  len)
    uart_div_modify(0, UART_CLK_FREQ / 115200);
    wifi_set_opmode(0);
    wifi_set_sleep_type( NONE_SLEEP_T );

    ETS_GPIO_INTR_DISABLE();// Disable gpio interrupts
    gpio_init();

    //Start os task
    system_init_done_cb(sdk_init_done_cb);
    //system_os_task(loop, user_procTaskPrio, user_procTaskQueue, user_procTaskQueueLen); //Task to Signal for later
}

OooOoOo, Look what I received yesterday. So, I really can take this two different ways.

1: The D.A. agrees with my stance that the court error’d in interpreting the Statues CVC 40801-40805 / CEC 1271(C), Doubtful 2: They don’t give two structured object’s about traffic cases and will leave it to the justices to reverse if there was indeed a legal error, More likely.

However, in any case, it’s best that they didn’t respond with a rebuttal and hey, this saves me from having to do an oral argument in front of the Justice Panel, which I wouldn’t of minded for the learning experience.

So, in my environment now we are having Isilon performance issues where a single file is taking anywhere from 20ms to 6 seconds in response time to deliver access to a file. I am currently working on getting Smart connect Advanced setup to get stronger control over our connects to our resource pools. We currently own 4 x210 bricks in our environment and have a file policy setup to replicate data to them for faster read access (SSD equipped). Now to my surprise while working with Dell it seems that if you create another pool, your x210 nodes can be a member of both pools and a virtual interface can be added to the x210’s so they then have two IP’s assigned to them. We can then assign a 2nd Smartconnect name to Pool1 and then point our highly sensitive servers to the new pool. This will give them a dedicated line to the SSD storage vs. having it fight with other servers on that same IP interface. I would be surprised if the difference was large but Dell seems to be pretty certain that well see an improvement even though it will still remain on the same physical devices.

Well this weekend turned out wonderful. I manage to finish this little piece of and this solution saved me a HUGE mount of heap space. This function I wrote to cycle through flash memory and format SprintF on the fly from Flash memory instead of having to double buffer the formatted HTML page. In my case my HTML page is around 4-8k depending on what I am loading, thats over half the ESP’s heapspace just to send results to the client, YIKES! Now those day’s are over 🙂

uint16 flashsprintf(char * dest, uint32_t address, char * Terminator, int n, ...)
{
    int i = 0;
    int val;
    int sizeofTerminator = os_strlen(Terminator);

    va_list ap;
    va_start(ap, n);

    uint16 destindex = 0;
    uint16 addressindex = 0;
    char buffer[4];
    bool percentflag = false; //This Flag is used for if the last char is a %
    while(true)
    {
        system_soft_wdt_feed();
        if (spi_flash_read(address+(addressindex*4), buffer, 4) != 0)
        {
            os_printf("Read failed at offset=0x%02x index=%d\r\n", address, index);
            return 0;
        }
        os_printf("string: %d - %c%c%c%c\r\n", (addressindex*4), *(buffer), *(buffer+1), *(buffer+2), *(buffer+3));
        addressindex++;
        for (i=0; i<=3; i++)
        {   
            if (percentflag)
            {
                switch(buffer[i]) 
                {
                    case 's'  :
                    val=va_arg(ap,char *);
                    destindex += os_sprintf(dest+destindex, "%s", val);
                    break; /* optional */

                    case 'd'  :
                    val=va_arg(ap,int);
                    destindex += os_sprintf(dest+destindex, "%d", val);
                    break; /* optional */

                    /* you can have any number of case statements */
                    default : /* Optional */
                    os_printf("Unknown ");

                }
                os_printf("Removing %%");
                percentflag = false;
                continue;
            }

            if (buffer[i] == '%')
            {
                os_printf("Setting %%");
                percentflag = true;
                continue;
            }
            else
            {
                *(dest+destindex)=buffer[i];
                destindex++;
                if (os_strncmp((dest+destindex-sizeofTerminator), Terminator, sizeofTerminator) == 0)
                {
                    *(dest+destindex)=0x00;
                    os_printf("Exiting");
                    return destindex;
                }
            }
        }
    }

    os_printf("done");
    va_end(ap);
    return destindex; //Returns SizeOf Resource
}

So lately I’ve been working on the Isilon quite a bit and we have a couple PAC servers that travel through the Netscalers here in our environment.
These netscalers are used as the Server’s default gateway for routing traffic. However using them as a source to route all data isn’t a great thing to do from a performance perspective, So some static routes are created to help make it’s backend NAS connections a bit faster.

First execute “Route Print” and note the Interface number, in this case 12,11,13,14,1

C:>route print

Interface List
12…02 00 4c 4f 4f 50 ……Npcap Loopback Adapter
11…ec b1 d7 3d 7d 8e ……Intel(R) Ethernet Connection I217-LM
13…00 50 56 c0 00 01 ……VMware Virtual Ethernet Adapter for VMnet1
14…00 50 56 c0 00 08 ……VMware Virtual Ethernet Adapter for VMnet8
1………………………Software Loopback Interface 1
===========================================================================

We would like to target 11 in this case.
Also note we need the word “MASK” in the middle or the command will not be parsed correctly
Giving -p for a persistent change, All connections to 10.246.x.240 will not route through 10.246.x.1

route -p add 10.246.x.240 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11
route -p add 10.246.x.241 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11
route -p add 10.246.x.242 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11
route -p add 10.246.x.243 MASK 255.255.255.255 10.246.x.1 METRIC 1 IF 11