/*
 1.PC connect the wifi : tunc5555  
              password :123456789
 2.Browser open: http://192.168.4.1/
 
 3.click the on or off button

#include <WebSockets.h>
#include <WebSockets4WebServer.h>
#include <WebSocketsClient.h>
#include <WebSocketsServer.h>
#include <WebSocketsVersion.h>

*/

#include <ESP8266WiFi.h>
#include <ESP8266WiFiMulti.h>
#include <WebSocketsServer.h>
//#include <Hash.h>
#include <ESP8266WebServer.h>
//#include <ESP8266mDNS.h>

#include <NTPClient.h>
#include <WiFiUdp.h>

#define USE_SERIAL Serial

static const char ssid[] = "Merry_2G";
static const char password[] = "Goodnews";

// MDNSResponder mdns;

static void writeLED(bool);

// ESP8266WiFiMulti WiFiMulti;

ESP8266WebServer server(80);
WebSocketsServer webSocket = WebSocketsServer(81);

static const char PROGMEM INDEX_HTML[] = R"rawliteral(
<!DOCTYPE html>
<html>
<head>
<meta name = "viewport" content = "width = device-width, initial-scale = 1.0, maximum-scale = 1.0, user-scalable=0">
<title>ESP8266 WebSocket Demo</title>
<style>
"body { background-color: #808080; font-family: Arial, Helvetica, Sans-Serif; Color: #000000; }"
</style>
<script>
var websock;
function start() {
  websock = new WebSocket('ws://' + window.location.hostname + ':81/');
  websock.onopen = function(evt) { console.log('websock open'); };
  websock.onclose = function(evt) { console.log('websock close'); };
  websock.onerror = function(evt) { console.log(evt); };
  websock.onmessage = function(evt) {
    console.log(evt);
    var e = document.getElementById('ledstatus');
    if (evt.data === 'ledon') {
      e.style.color = 'red';
    }
    else if (evt.data === 'ledoff') {
      e.style.color = 'black';
    }
    else {
      console.log('unknown event');
    }
  };
}
function buttonclick(e) {
  websock.send(e.id);
}
</script>
</head>
<body onload="javascript:start();">
<h1>ESP8266 WebSocket Demo</h1>
<div id="ledstatus"><b>LED</b></div>
<button id="ledon"  type="button" onclick="buttonclick(this);">On</button>
<button id="ledoff" type="button" onclick="buttonclick(this);">Off</button>
</body>
</html>
)rawliteral";


// GPIO#0 is for Adafruit ESP8266 HUZZAH board. Your board LED might be on 13.
const int LEDPIN = 0;
// Current LED status
bool LEDStatus;

// Commands sent through Web Socket
const char LEDON[] = "ledon";
const char LEDOFF[] = "ledoff";

void webSocketEvent(uint8_t num, WStype_t type, uint8_t * payload, size_t length)
{
  USE_SERIAL.printf("webSocketEvent(%d, %d, ...)\r\n", num, type);
  switch (type) {
  case WStype_DISCONNECTED:
    USE_SERIAL.printf("[%u] Disconnected!\r\n", num);
    break;
  case WStype_CONNECTED:
  {
               IPAddress ip = webSocket.remoteIP(num);
               USE_SERIAL.printf("[%u] Connected from %d.%d.%d.%d url: %s\r\n", num, ip[0], ip[1], ip[2], ip[3], payload);
               // Send the current LED status
               if (LEDStatus) {
                 webSocket.sendTXT(num, LEDON, strlen(LEDON));
               }
               else {
                 webSocket.sendTXT(num, LEDOFF, strlen(LEDOFF));
               }
  }
    break;
  case WStype_TEXT:
    USE_SERIAL.printf("[%u] get Text: %s\r\n", num, payload);

    if (strcmp(LEDON, (const char *)payload) == 0) {
      writeLED(true);
    }
    else if (strcmp(LEDOFF, (const char *)payload) == 0) {
      writeLED(false);
    }
    else {
      USE_SERIAL.println("Unknown command");
    }
    // send data to all connected clients
    webSocket.broadcastTXT(payload, length);
    break;
  case WStype_BIN:
    USE_SERIAL.printf("[%u] get binary length: %u\r\n", num, length);
    hexdump(payload, length);

    // echo data back to browser
    webSocket.sendBIN(num, payload, length);
    break;
  default:
    USE_SERIAL.printf("Invalid WStype [%d]\r\n", type);
    break;
  }
}

void handleRoot()
{
  server.send_P(200, "text/html", INDEX_HTML);
}

void handleNotFound()
{
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i<server.args(); i++){
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}

static void writeLED(bool LEDon)
{
  LEDStatus = LEDon;
  // Note inverted logic for Adafruit HUZZAH board
  if (LEDon) {
    digitalWrite(LEDPIN, 0);
  }
  else {
    digitalWrite(LEDPIN, 1);
  }
}

void setup()
{
  pinMode(LEDPIN, OUTPUT);
  writeLED(false);

  USE_SERIAL.begin(115200);

  //Serial.setDebugOutput(true);

  USE_SERIAL.println();
  USE_SERIAL.println();
  USE_SERIAL.println();

  for (uint8_t t = 4; t > 0; t--) {
    USE_SERIAL.printf("[SETUP] BOOT WAIT %d...\r\n", t);
    USE_SERIAL.flush();
    delay(1000);
  }

//  WiFiMulti.addAP(ssid, password);
//
//  while (WiFiMulti.run() != WL_CONNECTED) {
//    Serial.print(".");
//    delay(100);
//  }


//  WiFi.softAP(ssid, password);
//  IPAddress myIP = WiFi.softAPIP();
//  USE_SERIAL.print("AP IP address: ");
//  USE_SERIAL.println(myIP);

  // Wi-Fi 연결
  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
    USE_SERIAL.println("연결 중...");
  }
  USE_SERIAL.println("Wi-Fi 연결 성공!");
  USE_SERIAL.print("IP 주소: ");
  USE_SERIAL.println(WiFi.localIP());

//  USE_SERIAL.println("");
//  USE_SERIAL.print("Connected to ");
//  USE_SERIAL.println(ssid);
//  USE_SERIAL.print("IP address: ");
//  USE_SERIAL.println(WiFi.localIP());

// mdns 기능 windows 10에서는 문제가 있음
//
//  if (mdns.begin("espWebSock", WiFi.localIP())) {
//    USE_SERIAL.println("MDNS responder started");
//    mdns.addService("http", "tcp", 80);
//    mdns.addService("ws", "tcp", 81);
//  }
//  else {
//    USE_SERIAL.println("MDNS.begin failed");
//  }
//  USE_SERIAL.print("Connect to http://espWebSock.local or http://");
//  USE_SERIAL.println(WiFi.localIP());

  server.on("/", handleRoot);
  server.onNotFound(handleNotFound);

  server.begin();

  webSocket.begin();
  webSocket.onEvent(webSocketEvent);

}

void loop()
{
  webSocket.loop();
  server.handleClient();
}

'Embeded' 카테고리의 다른 글

Websocket with JSON  (0) 2023.10.26
Unix Timestamp 변환하기  (0) 2023.10.18
[ESP8266] Json in sming Framework  (0) 2023.02.04
Posted by 마인드파워
,

Websocket with JSON

Embeded 2023. 10. 26. 16:09

 

https://m1cr0lab-esp32.github.io/remote-control-with-websocket/websocket-and-json/


WebSocket Data Exchange with JSON

So far, we have only exchanged simple strings between the server and its clients using the WebSocket protocol. As long as the information transmitted remains simple to analyze, we can be satisfied with it. But sometimes we may need to exchange more complex data. In this case, it is preferable to structure the data so that it can be analysed more easily. This is where the JSON format comes in. JSON is a way to represent complex data structures as text. The resulting string is called a JSON document and can then be sent via the network or saved to a file.

For example, we may need to communicate more accurate information when the server needs to notify its clients with the LED status change:

```
{
    "device": "led",
    "status": "on",
    "time":   1591510722
}

```
The text above describes the prettifiedrepresentation in JSON format of an object composed of:

- a string named devicewith the value led,
- another string named statuswith the value on,
- an integer named timewith the value 1591510722.
JSON ignores spaces and line breaks, so the same object can be represented with the following minifiedJSON document:

```
{"device":"led","status":"on","time":1591510722}

```
Before the server can transmit this object to its clients, it will have to convert this structured data into a sequence of bytes. This is called serialization. In the context of JSON, serialization is the creation of a JSON document from an object in memory, and deserializationis the reverse operation.

Here the serialization remains quite simple and can be done easily with the sprintf()function:

```
sprintf(
    buffer,
    "{\"device\":\"%s\",\"status\":\"%s\",\"time\":\"%u\"}", // format
    "led",                                                   // device
    led.on ? "on" : "off",                                   // status
    millis()                                                 // time
);

```
You must of course provide a bufferlarge enough to hold the entire serialized data.

JSON makes it possible to structure much more complex data than that. It allows you to manage arrays of objects. Each object can encapsulate other objects in turn, or even arrays, etc.

As a result, serialization and deserialization processes can be laborious to implement. But, fortunately, there are plenty of libraries that can handle this for us. In this tutorial, we’ll use the excellentArduinoJsonlibrary developed by Benoît Blanchon.

ImportantThe following explanations are only compatible with version 6of the ArduinoJsonlibrary, which is the most recent version at the time of writing this tutorial.

My intention here is not to give you a complete course on the JSON format and its implementation with the ArduinoJsonlibrary. For that, please refer to its documentation, which is very complete. Nevertheless, I will present some basics to introduce you to its use.


Client notification


On the server side

When the LED changes state, the server transmits the new state to all clients. And so far, we’ve been doing it like this:

```
void notifyClients() {
    ws.textAll(led.on ? "on" : "off");
}

```
As long as the data to be transmitted is simple, one can simply proceed as follows, without the need to use a library specialized in the processing of the JSON format:

```
void notifyClients() {
    char buffer[17];
    sprintf(buffer, "{\"status\":\"%s\"}", led.on ? "on" : "off");
    ws.textAll(buffer);
}

```
Note that to store the string encoded in JSON format, a sufficiently large bufferis required. Indeed, depending on the state of the LED, onor off, the longest string to be encoded is the following:

```
{"status":"off"}

```
This string is exactly 16 characters long, to which it is necessary to think of adding the termination character \0of the strings in C. Our buffer must therefore be able to hold a maximum of 17characters. This is the reason for the following statement:

```
char buffer[17];

```
But let’s look instead at how to implement the same thing using the ArduinoJsonlibrary. First of all, we need to add the library to our project. To do this, we just need to edit our platformio.inifile and add a new dependency:

```
[env:esp32doit-devkit-v1]
platform      = espressif32
board         = esp32doit-devkit-v1
framework     = arduino
upload_speed  = 921600
monitor_speed = 115200
lib_deps      = ESP Async WebServer, ArduinoJson

```
Then we need to include the library header file at the beginning of our program:

```
#include <Arduino.h>
#include <SPIFFS.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>

```
One of the fundamental characteristics of the ArduinoJsonlibrary is its fixed memory allocation strategy. You first have to create a JsonDocumentto reserve a specified amount of memory. The memory of the JsonDocumentcan be either in the stackor in the heap. The location depends on the derived class you choose. If you use a StaticJsonDocument, it will be in the stack. If you use a DynamicJsonDocument, it will be in the heap.

Since our JsonDocumentis small, we can keep it in the stack. By using the stack, we reduce the size of the executable and improve the performance, because we avoid the overhead due to the management of the heap. We don’t need to engage a dynamic allocation strategy here, and we will avoid the problem of memory fragmentation at the same time.

When you create a JsonDocument, you must specify its capacity in bytes. In the case of a StaticJsonDocument, you set the capacity via a template parameter:

```
StaticJsonDocument<size> json;

```
As sizeis a template parameter, you cannot use a variable. Instead, you must use a constant expression, which means that the value must be computed at compile-time. The compiler manages the stack, so it needs to know the size of each variable when it compiles the program.

How to determine the capacity? To answer this question, you need to know what ArduinoJsonstores in the JsonDocument. ArduinoJsonneeds to store a data structure that mirrors the hierarchy of objects in the JSON document. In other words, the JsonDocumentcontains objects which relate to one another the same way they do in the JSON document.

Therefore, the capacity of the JsonDocumenthighly depends on the complexity of the JSON document. If it’s just one object with few members, like our example, a few dozens of bytes are enough. If it’s a massive JSON document, like OpenWeatherMap’s response, up to a hundred kilobytes are needed.

ArduinoJsonprovides macros for computing precisely the capacity of the JsonDocument. The macro to compute the size of an object is JSON_OBJECT_SIZE(). It takes one argument: the number of members in the object. Here is how to compute the capacity for our sample document:

```
const uint8_t size = JSON_OBJECT_SIZE(1);
StaticJsonDocument<size> json;

```
The JsonDocumentis currently empty. An empty JsonDocumentautomatically becomes an object when we add members to it. We do that with the subscript operator []:

```
const uint8_t size = JSON_OBJECT_SIZE(1);
StaticJsonDocument<size> json;
json["status"] = led.on ? "on" : "off";

```
The memory usage is now JSON_OBJECT_SIZE(1), so the JsonDocumentis full. When the JsonDocumentis full, you cannot add more members, so don’t forget to increase the capacity if you need.

Now, it’s time to serialize it into a JSON document. There are several ways to do that. Here we will look at how to write the JSON document to memory. We could use a String, but as you know, I prefer avoiding dynamic memory allocation. Instead, we’d use a good old char[]with enough space to receive the longest formatted string we need to encode:

```
char data[17];

```
Then, to produce a JSON document from a JsonDocument, we simply need to call serializeJson():

```
char data[17];
size_t len = serializeJson(json, data);

```
The serializeJson()function returns the effective length of the serialized JSON document. The value of this lenvariable will be useful for sending the JSON document to WebSocket clients. Here is the complete definition of the rewritten notifyClients()function:

```
void notifyClients() {
    const uint8_t size = JSON_OBJECT_SIZE(1);
    StaticJsonDocument<size> json;
    json["status"] = led.on ? "on" : "off";

    char data[17];
    size_t len = serializeJson(json, data);
    ws.textAll(data, len);
}

```
Using the ArduinoJsonlibrary on this very simple case probably seems overkill, and you’re right. But I wanted to make you aware of its use, which will prove extremely life-saving in the case of more complex data. I encourage you to carefully read the documentationof this library, which details many useful use cases.


On the client side

Now that the server broadcasts its notifications in JSON format, we need to take this into account on the client side and rewrite the onMessage()function that receives these notifications in the index.jsfile:

```
function onMessage(event) {
    let data = JSON.parse(event.data);
    document.getElementById('led').className = data.status;
}

```
You can see that this new data processing is extremely simple. We start by decoding the received object in JSON format to make it a Javascript object. And then we can easily read the value of its statusmember. It’s as simple as that!


Server notification

This time, when the user presses the Togglebutton on the web interface, we will send a notification to the server in the form of a message in JSON format.


On the client side

We’ll slightly modify the onToggle()function in the index.jsfile to send the following JSON message:

```
{"action":"toggle"}

```
It’s quite simple:

```
function onToggle(event) {
    websocket.send(JSON.stringify({'action':'toggle'}));
}

```

On the server side

To make things a little easier, we assume here that the structure of the expected JSON message is known in advance. The JSON document consists of a JSON object with a single member named action, whose value is a string.

We will rewrite the handleWebSocketMessage()function to handle messages received in JSON format:

```
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
    AwsFrameInfo *info = (AwsFrameInfo*)arg;
    if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {

        // We'll see in the following how to decode the received message
        
    }
}

```
Since our JsonDocumentis small, we can keep it in the stack:

```
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
    AwsFrameInfo *info = (AwsFrameInfo*)arg;
    if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {

        const uint8_t size = JSON_OBJECT_SIZE(1);
        StaticJsonDocument<size> json;
        
    }
}

```
Now that the JsonDocumentis ready, we can parse the input data with the deserializeJson()function:

```
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
    AwsFrameInfo *info = (AwsFrameInfo*)arg;
    if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {

        const uint8_t size = JSON_OBJECT_SIZE(1);
        StaticJsonDocument<size> json;
        DeserializationError err = deserializeJson(json, data);
        
    }
}

```
The deserializeJson()function returns a DeserializationErrorthat tells whether the operation was successful. DeserializationErrorconverts implicitly to bool, so we don’t need to identify the nature of the error by searching for the error code and comparing it to the predefined constants of the DeserializationErrorclass. We can simply write:

```
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
    AwsFrameInfo *info = (AwsFrameInfo*)arg;
    if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {

        const uint8_t size = JSON_OBJECT_SIZE(1);
        StaticJsonDocument<size> json;
        DeserializationError err = deserializeJson(json, data);
        if (err) {
            Serial.print(F("deserializeJson() failed with code "));
            Serial.println(err.c_str());
            return;
        }
        
    }
}

```
If no error occurs at the time of deserialization, we can extract the value of the actionmember and compare it to the expected value, i.e. toggle:

```
void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
    AwsFrameInfo *info = (AwsFrameInfo*)arg;
    if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {

        const uint8_t size = JSON_OBJECT_SIZE(1);
        StaticJsonDocument<size> json;
        DeserializationError err = deserializeJson(json, data);
        if (err) {
            Serial.print(F("deserializeJson() failed with code "));
            Serial.println(err.c_str());
            return;
        }

        const char *action = json["action"];
        if (strcmp(action, "toggle") == 0) {
            led.on = !led.on;
            notifyClients();
        }
        
    }
}

```
If successful, the status of the LED is reversed and all connected clients are notified.

There you go! This time we’ve come full circle.You can upload the contents of the datafolder to the SPIFFS to update the index.jsfile:


Then compile and upload the C++ program to the ESP32. Reload the web user interface in the browser and you will see that everything works exactly as in the previous chapter, except that now the server and clients communicate with messages in JSON format.

You can now update the baseline project by going to the remote-control-with-websocketdirectory and executing the following gitcommand:

```
git checkout v1.0

```
You can also download the updated main.cppand index.jsfiles and replace yours in your own project:


main.cpp


index.js

Here is the complete code for this chapter:


Server side

```
/**
 * ----------------------------------------------------------------------------
 * ESP32 Remote Control with WebSocket
 * ----------------------------------------------------------------------------
 * © 2020 Stéphane Calderoni
 * ----------------------------------------------------------------------------
 */

#include <Arduino.h>
#include <SPIFFS.h>
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <ArduinoJson.h>

// ----------------------------------------------------------------------------
// Definition of macros
// ----------------------------------------------------------------------------

#define LED_PIN   26
#define BTN_PIN   22
#define HTTP_PORT 80

// ----------------------------------------------------------------------------
// Definition of global constants
// ----------------------------------------------------------------------------

// Button debouncing
const uint8_t DEBOUNCE_DELAY = 10; // in milliseconds

// WiFi credentials
const char *WIFI_SSID = "YOUR_WIFI_SSID";
const char *WIFI_PASS = "YOUR_WIFI_PASSWORD";

// ----------------------------------------------------------------------------
// Definition of the LED component
// ----------------------------------------------------------------------------

struct Led {
    // state variables
    uint8_t pin;
    bool    on;

    // methods
    void update() {
        digitalWrite(pin, on ? HIGH : LOW);
    }
};

// ----------------------------------------------------------------------------
// Definition of the Button component
// ----------------------------------------------------------------------------

struct Button {
    // state variables
    uint8_t  pin;
    bool     lastReading;
    uint32_t lastDebounceTime;
    uint16_t state;

    // methods determining the logical state of the button
    bool pressed()                { return state == 1; }
    bool released()               { return state == 0xffff; }
    bool held(uint16_t count = 0) { return state > 1 + count && state < 0xffff; }

    // method for reading the physical state of the button
    void read() {
        // reads the voltage on the pin connected to the button
        bool reading = digitalRead(pin);

        // if the logic level has changed since the last reading,
        // we reset the timer which counts down the necessary time
        // beyond which we can consider that the bouncing effect
        // has passed.
        if (reading != lastReading) {
            lastDebounceTime = millis();
        }

        // from the moment we're out of the bouncing phase
        // the actual status of the button can be determined
        if (millis() - lastDebounceTime > DEBOUNCE_DELAY) {
            // don't forget that the read pin is pulled-up
            bool pressed = reading == LOW;
            if (pressed) {
                     if (state  < 0xfffe) state++;
                else if (state == 0xfffe) state = 2;
            } else if (state) {
                state = state == 0xffff ? 0 : 0xffff;
            }
        }

        // finally, each new reading is saved
        lastReading = reading;
    }
};

// ----------------------------------------------------------------------------
// Definition of global variables
// ----------------------------------------------------------------------------

Led    onboard_led = { LED_BUILTIN, false };
Led    led         = { LED_PIN, false };
Button button      = { BTN_PIN, HIGH, 0, 0 };

AsyncWebServer server(HTTP_PORT);
AsyncWebSocket ws("/ws");

// ----------------------------------------------------------------------------
// SPIFFS initialization
// ----------------------------------------------------------------------------

void initSPIFFS() {
  if (!SPIFFS.begin()) {
    Serial.println("Cannot mount SPIFFS volume...");
    while (1) {
        onboard_led.on = millis() % 200 < 50;
        onboard_led.update();
    }
  }
}

// ----------------------------------------------------------------------------
// Connecting to the WiFi network
// ----------------------------------------------------------------------------

void initWiFi() {
  WiFi.mode(WIFI_STA);
  WiFi.begin(WIFI_SSID, WIFI_PASS);
  Serial.printf("Trying to connect [%s] ", WiFi.macAddress().c_str());
  while (WiFi.status() != WL_CONNECTED) {
      Serial.print(".");
      delay(500);
  }
  Serial.printf(" %s\n", WiFi.localIP().toString().c_str());
}

// ----------------------------------------------------------------------------
// Web server initialization
// ----------------------------------------------------------------------------

String processor(const String &var) {
    return String(var == "STATE" && led.on ? "on" : "off");
}

void onRootRequest(AsyncWebServerRequest *request) {
  request->send(SPIFFS, "/index.html", "text/html", false, processor);
}

void initWebServer() {
    server.on("/", onRootRequest);
    server.serveStatic("/", SPIFFS, "/");
    server.begin();
}

// ----------------------------------------------------------------------------
// WebSocket initialization
// ----------------------------------------------------------------------------

void notifyClients() {
    const uint8_t size = JSON_OBJECT_SIZE(1);
    StaticJsonDocument<size> json;
    json["status"] = led.on ? "on" : "off";

    char data[17];
    size_t len = serializeJson(json, data);
    ws.textAll(data, len);
}

void handleWebSocketMessage(void *arg, uint8_t *data, size_t len) {
    AwsFrameInfo *info = (AwsFrameInfo*)arg;
    if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {

        const uint8_t size = JSON_OBJECT_SIZE(1);
        StaticJsonDocument<size> json;
        DeserializationError err = deserializeJson(json, data);
        if (err) {
            Serial.print(F("deserializeJson() failed with code "));
            Serial.println(err.c_str());
            return;
        }

        const char *action = json["action"];
        if (strcmp(action, "toggle") == 0) {
            led.on = !led.on;
            notifyClients();
        }

    }
}

void onEvent(AsyncWebSocket       *server,
             AsyncWebSocketClient *client,
             AwsEventType          type,
             void                 *arg,
             uint8_t              *data,
             size_t                len) {

    switch (type) {
        case WS_EVT_CONNECT:
            Serial.printf("WebSocket client #%u connected from %s\n", client->id(), client->remoteIP().toString().c_str());
            break;
        case WS_EVT_DISCONNECT:
            Serial.printf("WebSocket client #%u disconnected\n", client->id());
            break;
        case WS_EVT_DATA:
            handleWebSocketMessage(arg, data, len);
            break;
        case WS_EVT_PONG:
        case WS_EVT_ERROR:
            break;
    }
}

void initWebSocket() {
    ws.onEvent(onEvent);
    server.addHandler(&ws);
}

// ----------------------------------------------------------------------------
// Initialization
// ----------------------------------------------------------------------------

void setup() {
    pinMode(onboard_led.pin, OUTPUT);
    pinMode(led.pin,         OUTPUT);
    pinMode(button.pin,      INPUT);

    Serial.begin(115200); delay(500);

    initSPIFFS();
    initWiFi();
    initWebSocket();
    initWebServer();
}

// ----------------------------------------------------------------------------
// Main control loop
// ----------------------------------------------------------------------------

void loop() {
    ws.cleanupClients();

    button.read();

    if (button.pressed()) {
        led.on = !led.on;
        notifyClients();
    }
    
    onboard_led.on = millis() % 1000 < 50;

    led.update();
    onboard_led.update();
}

```

Client side

```
/**
 * ----------------------------------------------------------------------------
 * ESP32 Remote Control with WebSocket
 * ----------------------------------------------------------------------------
 * © 2020 Stéphane Calderoni
 * ----------------------------------------------------------------------------
 */

var gateway = `ws://${window.location.hostname}/ws`;
var websocket;

// ----------------------------------------------------------------------------
// Initialization
// ----------------------------------------------------------------------------

window.addEventListener('load', onLoad);

function onLoad(event) {
    initWebSocket();
    initButton();
}

// ----------------------------------------------------------------------------
// WebSocket handling
// ----------------------------------------------------------------------------

function initWebSocket() {
    console.log('Trying to open a WebSocket connection...');
    websocket = new WebSocket(gateway);
    websocket.onopen    = onOpen;
    websocket.onclose   = onClose;
    websocket.onmessage = onMessage;
}

function onOpen(event) {
    console.log('Connection opened');
}

function onClose(event) {
    console.log('Connection closed');
    setTimeout(initWebSocket, 2000);
}

function onMessage(event) {
    let data = JSON.parse(event.data);
    document.getElementById('led').className = data.status;
}

// ----------------------------------------------------------------------------
// Button handling
// ----------------------------------------------------------------------------

function initButton() {
    document.getElementById('toggle').addEventListener('click', onToggle);
}

function onToggle(event) {
    websocket.send(JSON.stringify({'action':'toggle'}));
}

```

WebSocket Data ExchangeTime for Discussion

'Embeded' 카테고리의 다른 글

ESP8266 websocket (HTML 내장)  (0) 2023.10.28
Unix Timestamp 변환하기  (0) 2023.10.18
[ESP8266] Json in sming Framework  (0) 2023.02.04
Posted by 마인드파워
,

Unix Timestamp 변환하기

Embeded 2023. 10. 18. 22:36
typedef uint32_t timestamp_t;  //seconds  타임 스탬프 변수형

// 데이트타임 구조체
typedef struct {
  uint16_t    year;
  uint8_t     month;
  uint8_t     day;  
  uint8_t     hour;  
  uint8_t     minute;
  uint8_t     second;
  uint8_t     week;
  uint8_t     weekday;
} datetime_t;

// 1일을 초로
#define ONE_DAY  (1*60*60*24)

// UTC 시작 시간
#define UTC_TIME_WEEKDAY_OFFSET (4)  /* 1970,1,1은 목요일이기때문에 */

//날짜                    x, 1월, 2월 ..... 11월, 12월
uint8_t month_days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

// Globals
time_t now;   // this are the seconds since Epoch (1970) - UTC
tm tm;        // the structure tm holds time information in a more convenient way
//요일 얻기
uint8_t timestamp_to_weekday(timestamp_t timestamp_sec)
{
  uint8_t result=(timestamp_sec / ONE_DAY + UTC_TIME_WEEKDAY_OFFSET) % 7;
  if (result==0){
    result = 7;
  }
  return result;
}

//윤달 확인
int is_leap_year(uint16_t year)
{
  if ( year % 4 == 0 && ((year % 100) != 0) || ((year % 400)==0) ) {
    return true;
  } else {
    return false;
  }
}

//UTC 타임 스탬프를 날짜로 변환
void utc_timestamp_to_date(timestamp_t timestamp, datetime_t* datetime)
{
  uint8_t month;
  uint32_t days;
  uint16_t days_in_year;
  uint16_t year;
  timestamp_t second_in_day;

  //날짜
  second_in_day = (timestamp + (9*60*60)) % ONE_DAY;

  //초
  datetime->second=second_in_day%60;

  //분
  second_in_day /= 60;
  datetime->minute=second_in_day%60;

  //시
  second_in_day /=60;
  datetime->hour=second_in_day % 24;

  //1970-1-1 부터 현재까지 총 일수
  days = (timestamp + (9*60*60)) / ONE_DAY;

  //days를 계속 차감하면서 해당 년도 계산
  for (year=1970;year<=2100;year++){
    if(is_leap_year(year))
      days_in_year=366;
    else
      days_in_year=365;

    if(days>=days_in_year)
      days -= days_in_year;
    else
      break;
   
  }

  //년
  datetime->year=year;

  //요일
  datetime->weekday=timestamp_to_weekday(timestamp);

  //해당 년도 1월1일을 기준으로 지금까지의 주(week) 계산
  datetime->week=(days+11-datetime->weekday)/7;

  //월 계산
  if(is_leap_year(datetime->year))  //윤달의 경우 2월이 29일이다.
    month_days[2]=29;
  else
    month_days[2]=28;

  //년도와 마찬가지로 일에서 계속 차감해서 찾는다.
  for (month=1; month<=12; month++){
    if (days>=month_days[month])
      days -= month_days[month];
    else
      break;  

  }

  datetime->month=month;
  datetime->day=days+1;
 
  Serial.print(datetime->year);
  Serial.print(datetime->month);
  Serial.print(datetime->day);
  Serial.print(datetime->hour);
  Serial.println(datetime->minute);

}

'Embeded' 카테고리의 다른 글

ESP8266 websocket (HTML 내장)  (0) 2023.10.28
Websocket with JSON  (0) 2023.10.26
[ESP8266] Json in sming Framework  (0) 2023.02.04
Posted by 마인드파워
,

https://jeong-pro.tistory.com/155

Posted by 마인드파워
,

 

example of a Python Flask application that uses a PostgreSQL database to store the daily work of employees:

 

import psycopg2
from flask import Flask, request, render_template
app = Flask(__name__)

def get_conn():
    conn = psycopg2.connect(
        host="localhost",
        database="daily_work",
        user="postgres",
        password="secret"
    )
    return conn

@app.route("/")
def index():
    return render_template("index.html")

@app.route("/submit_work", methods=["POST"])
def submit_work():
    work = request.form["work"]
    conn = get_conn()
    cur = conn.cursor()
    cur.execute("INSERT INTO work (description) VALUES (%s)", (work,))
    conn.commit()
    cur.close()
    conn.close()
    return "Work submitted successfully!"

if __name__ == "__main__":
    app.run()

This code uses the Flask web framework and the psycopg2 library to interact with a PostgreSQL database. The get_conn function returns a connection to the database, and the submit_work route uses this connection to insert the work submitted by the employee into the work table. You'll need to create this table and the daily_work database using a tool like the psql client or a GUI client like pgAdmin. The table can be created with the following SQL command:

 

CREATE TABLE work (
    id serial PRIMARY KEY,
    description text NOT NULL
);
<html>
  <head>
    <title>Enter daily work</title>
  </head>
  <body>
    <form action="/submit_work" method="post">
      <textarea name="work"></textarea>
      <input type="submit" value="Submit work">
    </form>
  </body>
</html>

 

sample code to show the contents stored in the PostgreSQL database as a table:

import psycopg2
from flask import Flask, render_template
app = Flask(__name__)

def get_conn():
    conn = psycopg2.connect(
        host="localhost",
        database="daily_work",
        user="postgres",
        password="secret"
    )
    return conn

@app.route("/")
def index():
    conn = get_conn()
    cur = conn.cursor()
    cur.execute("SELECT * FROM work")
    work = cur.fetchall()
    cur.close()
    conn.close()
    return render_template("work_table.html", work=work)

if __name__ == "__main__":
    app.run()

 

php

<html>
  <head>
    <title>Daily work</title>
  </head>
  <body>
    <table>
      <thead>
        <tr>
          <th>ID</th>
          <th>Description</th>
        </tr>
      </thead>
      <tbody>
        {% for row in work %}
        <tr>
          <td>{{ row[0] }}</td>
          <td>{{ row[1] }}</td>
        </tr>
        {% endfor %}
      </tbody>
    </table>
  </body>
</html>

This code uses the Flask web framework and the psycopg2 library to interact with a PostgreSQL database. The index route retrieves the work stored in the work table using a SQL query, and the template work_table.html displays the work as a table.

Posted by 마인드파워
,

Android 앱 개발에 가장 적합한 도구는 개인 선호도와 프로젝트 요구 사항에 따라 다르지만 널리 사용되는 옵션은 다음과 같습니다.

  1. Android Studio: Android 앱 개발을 위한 공식 통합 개발 환경(IDE)입니다.
  2. React Native: JavaScript 및 React를 사용하여 네이티브 앱을 구축하기 위한 프레임워크입니다.
  3. Flutter: 단일 코드 베이스에서 고성능, 충실도, iOS 및 Android용 앱을 빌드하기 위한 오픈 소스 프레임워크입니다.
  4. Xamarin: C#을 사용하여 Android 및 iOS용 네이티브 앱을 만들 수 있는 플랫폼 간 개발 도구입니다.

궁극적으로 사용할 도구의 선택은 기술 능력, 예산 및 프로젝트 요구 사항에 따라 다릅니다.

 

 

'Developer' 카테고리의 다른 글

sample python code with PostgreSQL  (0) 2023.02.04
Posted by 마인드파워
,

Sming framework is a C++ framework for developing applications for ESP8266 and ESP32 microcontrollers. To encode and decode JSON data in Sming, you can use the JsonObjectStream library that is included in the framework.

 

Here's an example of encoding JSON data in Sming:

 

#include <JsonObjectStream.h>
#include <Wire.h>

void setup() {
  Serial.begin(115200);
  DynamicJsonDocument doc(1024);
  JsonObject data = doc.to<JsonObject>();
  data["device"] = "ESP8266";
  data["value"] = 42;
  String json;
  serializeJson(doc, json);
  Serial.println(json);
}

void loop() {
}

 

And here's an example of decoding JSON data in Sming:

#include <JsonObjectStream.h>
#include <Wire.h>

void setup() {
  Serial.begin(115200);
  String json = "{\"device\":\"ESP8266\",\"value\":42}";
  DynamicJsonDocument doc(1024);
  DeserializationError error = deserializeJson(doc, json);
  if (error) {
    Serial.println("Deserialization failed: " + error.c_str());
    return;
  }
  JsonObject data = doc.as<JsonObject>();
  Serial.println("device: " + data["device"].as<String>());
  Serial.println("value: " + data["value"].as<int>());
}

void loop() {
}

'Embeded' 카테고리의 다른 글

ESP8266 websocket (HTML 내장)  (0) 2023.10.28
Websocket with JSON  (0) 2023.10.26
Unix Timestamp 변환하기  (0) 2023.10.18
Posted by 마인드파워
,

Simple is Best !!

사설 2020. 10. 9. 19:48

여기 티스토리에 사설 카테고리에 5년만에 글을 쓰네요.. 

그 동안 많은 일이 있었다.

인생의 몇 고비중에 한 고비 추간된것 같다.

 

삶이 너무 복잡하다.

유혹하는 것도 많고.

그 유혹 다 들어주고 살면....  바보가 되지 않을까..

 

최대한 단순화 하자..

아직은 50살의 학생이니.. 공부에도 집중..ㅋ 

내년에 동양미래대 졸업과 동시에 고려사이버 3학년 편입을 생각중이다.

 

졸업 작품도 만들어야 하는데..

진행이 순조롭지 않다.. 모든 일이 그렇듯이..

 

오늘 강남에서 사는 아들을 만나고 오면서 문득 든 생각은 삶을 단순화 하자...

 

 

건강을 위해 운동도 해야 하고,

시력도 좋아지는 훈련도 해야 하고

영어 공부도 해야 하고..

학교 공부도 해야 하고..

직장도 다녀야 하고..

가정 생활..

할게 너무 많다..

이럴수록 최대한 단순화 하고,, 집중해야 하는데...ㅠ.ㅠ

 

 

 

'사설' 카테고리의 다른 글

글 쓰기 연습  (0) 2015.08.02
무시해 주셔서 감사합니다.  (0) 2014.07.14
기술보다 마음이 먼저다.  (0) 2013.07.15
Posted by 마인드파워
,

알렉세예프

좋은글 2016. 11. 30. 21:41


1970
년도 미국 콤롬버스 세계 역도선구권 대회를 앞두고 전세계가 시끄러웠어요
바실리 알렉세예프
이사람이 강력한 금메달 우승 후보예요
틀림없이 금메달은 따놓은 당상이예요
마의 500파운드, 227kg 들어올릴것인가 하는것이 역도의 관심이였어요
어떤 선수도 500파운드를 드는 사람은 아무도 없었어요
모든 선수들의 생각에는 500파운드는 인간이 절대로 들어올릴수 없는 무게인데 과연 알렉세예프는 들어올릴수 있을까? 하는데 관심이 있었는데 결승에 나와서 들어올렸는데
500
파운드가 아니라 499파운드를 들어올렸어요
500
파운드는 부담이 되니까 499파운드에 도전을 한거예요
사람들은 499파운드가 뭐야, 1파운드를 더해서 500파운드를 들어올리지 하지만, 만약에 못올리면 금메달을 놓칠수 있으니까 금메달이라도 확실하게 따야겠다해서 금메달은 땄는데 세계 신기록은 이루지 못한거예요
500
파운드를 하지 499파운드가 뭐야 하며 사람들이 웅성거리고 있는 이때 안내방송이 울려 펴졌어요
"
주최측의 실수로 역기 무게가 잘못 측정되었습니다
방금 알렉세예프 선수가 들어 올린것은 499파운드가 아니라 501.5파운드를 들어올렸습니다 정정합니다." 하고 방송이 나오자 사람들이 인간의 한계를 넘은것을 좋아하고 박수를 보내며 기뻐하는 거예요
만일 알렉세예프가 무게가 501.5파운드 라고 생각했으면 심적으로 부담이 되어서 들었을텐데 499파운드 라고 생각하고 들어올렸는데 인간의 한계를 넘은거예요
그해에 놀랍게도 7명이나 500파운드를 들어올린거예요
알렉세예프가 기록을 깨고 나니까, '~ 500파운드를 인간이 들어올릴 있네. 우리가 지금까지 못들어 올렸지?'
들어 올리고, 올리고는 무게 1파운드의 차이가 아니라 생각차이라는 거지요
몸에 병이 걸리고, 암에 걸린사람들이 내가 암에 걸려서 얼마 못산다
어디 조용한데 가서 휴양해야 겠다 하면 일찍 죽는데요

미국 달라스에 세계에서 유명한 암센타가 있어요
삼성 이건희회장님도 삼성병원도 낫는 병원인데 여기서 치료 안받고 미국 달라스 암센타에서 수술을 받았대요
암센타의 유명한 의사가 한국사람이예요
의신 박사, 최고의 유명한 의사상을 두번이나 받았답니다
박사님이 뭐라고 하느냐면
암이 걸리면 제일 빨리 죽는 사람이 병에 대해 가장 잘아는 의사, 간호사랍니다
그다음에 나라로 보면 한국사람이 제일 빨리 죽는답니다. 왜냐면
한국사람들은 암에 걸린걸 알면 일을 그만두고, 직장을 그만두고 병원에 들어가기 시작한데요, 수술을 한데요, 방사선 치료, 항암치료를 하고 공기좋은 조용한 산속에 들어가서 투병생활을 하면서 죽는대요, 일찍 죽는대요
그안에 들어가서 뭐만 생각하겠어요.
암만 생각한대요. 암만 생각해도 죽지! 그래요? 안그래요?
다른나라 사람은 암에 걸렸어도 직장은 다닌대요, 같이 일상생활을 하니까 생각에 그만큼 안빠지는데 우리 한국 사람은 암만 생각한데요
인간의 생각이라는게 1파운드 소고기 한근도 안되는 그것도 못들어 올린다니까요
아무도 못든다는 인간의 생각이 고정이 되어버린거예요

생각이 고정되니까 그런거예요
머릿속에 "한계" "불가능"이라는 독초가 한번 뿌리를 내리게 되면
생각들은 당신이 분명히 수있는 일들조차 도전할수 없도록 만든다는 글이 있어요
이길수 있는데도 나는 한계가 여기까지야 나는 불가능해. 암은 못고쳐, 어려움은 안되는 구나. 하며 불가능과 한계에 빠져 있으니까 안되는거예요
알렉세예프 이전의 선수들은 500파운드를 들수 있는데 한계와 불가능이라는 잘못된 믿음 때문이란걸 기억해야 합니다

우리 다같이 큰소리로 읽어 보겠습니다


"
한계는 없다. 한계라고 믿는 당신만 있을 뿐이다"


한계는 있어요? 없어요? 없어요
한국사람이 암이 걸리면 일도 안하고 조용한 곳에서 투병하면서 암만 생각하는데 암만 생각하니까 죽지요
우리가 일상적으로 생활을 하고, 마인드 교육을 받은 사람은 암따라 안가요
이제 우리는 마음 따라가요. 알겠어요?
마음에 근육하고 마음이 힘이 있으면 되요. 그렇지요?
몸은 건강식을 먹어서 힘이 되지만 마음의 힘은 마인드 교육이예요
여러분 한계가 있어요? 없어요?
마인드 교육을 들으신 분들은 100 까지 살수있습니다
마인드 강연들으면서 건강하게, 튼튼하게 사셔야죠
그래서 한계는 없습니다. 마음에 믿음을 가진 사람은
마음의 한계를 이길수 있습니다
무슨 어려움이 있어도 한계를 넘어버립니다
알렉세예프가 세계신기록을 세운것은 생각의 세계를 넘은 것이라고 했지요 


생각의 세계를 넘은 사람은 암도 정복합니다



자기계발서추천 베스트셀러 [마음을파는백화점]
















Posted by 마인드파워
,



[한겨레][내 삶의 주인 되기] "아이에게 냉정했던 어머니 원망했던 주부 엄마 닮아가는 내가 싫어요"



Q & A 로 진행된 위 제목의 기사가 엄마가 아닌 아빠인 내게도 공감이 많이 되어 공유합니다.



어린시절 엄마가 싫었던 질문자는 자신은 엄마가 되면 절대 자기 엄마처럼 되지 말아야지 했는데


자신도 동일하게 그렇게 하고 있는것을 보며 자괴감에 빠진다는 질문에 대한 답변입니다.


이 세상 엄마들이 한 번쯤은 읽었봤으면 하는 내용이네요






박미라 심리상담가·<천만번 괜찮아> <치유하는 글쓰기> 저자

서울살이 길라잡이 서울앤(www.seouland.com) 취재팀 편집



'좋은글' 카테고리의 다른 글

알렉세예프  (0) 2016.11.30
나는 잘 하고 있어 ~  (0) 2014.06.15
모든 사람은 천재다 (From 행경)  (0) 2014.02.24
젊은이들이여, 두려움과 싸워라!  (0) 2013.01.28
만약 내가 (If I can ..)  (0) 2011.10.09
Posted by 마인드파워
,