нет неправильно. команда serializeJson(doc, output); делает - serializeJson() serializes a JsonDocument to create a minified JSON document, i.e. a document without spaces or line break between values.
то есть оптимизирует и удаляет лишнее чтоб было меньше отправлять а отправляешь все равно через ws.textAll
Смотри, если у тебя небольшой “одноуровневый“ JSON то можно его руками собирать и отправлять без библиотеки. Самое главное не отправлять так
for (int n = 0; n <= 7; n++) {
if (switchVar1 & (1 << n)) { // array[0-7]
ws.textAll(String(1));
}
или так
ws.textAll(String("TEMP:") + tempC);
ws.textAll(String("HUMID:") + byte(humidity));
ws.textAll(String("SENSOR:") + byte(sensor));
Сначала собираешь данные отправки в одну строку, не важно как, с библиотекой или без, и потом одним пакетом отправляешь.
Может придут щас умные люди и научат нас отправлять данные по ws пачками, главное чтоб не в теории, а с рабочим кодом, но я так не умею!
Вот смотри, рабочие коды, проверено работает, от твоего отличается только тем что данные генерятся рандомно а не берутся с сенсоров.
index.h
const char htmlPage[] PROGMEM = R"rawliteral(
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PIN Display</title>
<style>
body {
font-family: Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.container {
background: white;
padding: 40px;
border-radius: 20px;
box-shadow: 0 20px 60px rgba(0,0,0,0.3);
text-align: center;
}
h1 {
margin: 0 0 30px 0;
color: #333;
}
.pin-display {
display: flex;
gap: 10px;
justify-content: center;
margin-bottom: 20px;
}
.pin-digit {
width: 50px;
height: 60px;
background: #f0f0f0;
border: 2px solid #667eea;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 32px;
font-weight: bold;
color: #333;
transition: all 0.3s ease;
}
.pin-digit.active {
background: #667eea;
color: white;
transform: scale(1.1);
}
.status {
margin-top: 20px;
padding: 10px;
border-radius: 8px;
font-size: 14px;
}
.status.connected {
background: #d4edda;
color: #155724;
}
.status.disconnected {
background: #f8d7da;
color: #721c24;
}
</style>
</head>
<body>
<div class="container">
<h1>PIN Мониторинг</h1>
<div class="pin-display" id="pinDisplay"></div>
<div class="status disconnected" id="status">Отключено</div>
</div>
<script>
// адрес WebSocket сервера
const WS_URL = 'ws://' + window.location.host + '/ws';
let ws;
const pinDisplay = document.getElementById('pinDisplay');
const statusEl = document.getElementById('status');
// динамически нарисуем 8 элементов для отображения PIN
for (let i = 0; i < 8; i++) {
const digit = document.createElement('div');
digit.className = 'pin-digit';
digit.textContent = '0';
digit.id = `pin-${i}`;
pinDisplay.appendChild(digit);
}
function connectWebSocket() {
ws = new WebSocket(WS_URL);
ws.onopen = () => {
console.log('WebSocket подключен');
statusEl.textContent = 'Подключено';
statusEl.className = 'status connected';
};
ws.onmessage = (event) => {
try {
const data = JSON.parse(event.data);
if (data.pin && Array.isArray(data.pin)) {
updatePinDisplay(data.pin);
}
} catch (error) {
console.error('Ошибка парсинга JSON:', error);
}
};
ws.onerror = (error) => {
console.error('WebSocket ошибка:', error);
statusEl.textContent = 'Ошибка подключения';
statusEl.className = 'status disconnected';
};
ws.onclose = () => {
console.log('WebSocket отключен');
statusEl.textContent = 'Отключено';
statusEl.className = 'status disconnected';
// Переподключение через 3 секунды
setTimeout(connectWebSocket, 3000);
};
}
function updatePinDisplay(pinArray) {
pinArray.forEach((value, index) => {
const digitEl = document.getElementById(`pin-${index}`);
if (digitEl) {
digitEl.textContent = value;
// подсветим активные (если значение 1)
if (value === 1) {
digitEl.classList.add('active');
} else {
digitEl.classList.remove('active');
}
}
});
}
// Запускаем подключение
connectWebSocket();
</script>
</body>
</html>
)rawliteral";
ino
//#include <ArduinoJson.h>
//#include <ArduinoJson.hpp>
#ifdef ARDUINO_ARCH_ESP32
#include <WiFi.h>
#include <AsyncTCP.h>
#else
#include <ESP8266WiFi.h>
#include <ESPAsyncTCP.h>
#endif
#include <ESPAsyncWebServer.h>
#include "index.h"
const char *ssid = "***";
const char *password = "***";
#ifdef ARDUINO_ARCH_ESP8266
const int LED_PIN = LED_BUILTIN;
#define LED_ON LOW
#define LED_OFF HIGH
byte const SENSOR_PIN = A0;
#else
const int LED_PIN = 2;
#define LED_ON HIGH
#define LED_OFF LOW
byte const SENSOR_PIN = 34;
#endif
//#include "DHT.h" //https://github.com/adafruit/Adafruit_Sensor
#define DHTPIN D1
#define DHTTYPE DHT11
//DHT dht(DHTPIN, DHTTYPE);
bool ledState = false;
//byte const pinLED = LED_BUILTIN;
int sensor = 0;
float humidity = 0;
float tempC = 0;
float tempF = 0;
AsyncWebServer server(80);
AsyncWebSocket ws("/ws");
//#define LATCHPIN D2 //GREEN 9 chip CD4021
//#define DATAPIN D3 //YELLOW 3 chip CD4021
//#define CLOCKPIN D4 // GREY 10 chip CD4021
byte switchVar1 = 72; //01001000 регистр сдвига CD4021
byte switchVar2 = 159; //10011111
void setup() {
Serial.begin(115200);
while (!Serial) { ; }
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LED_OFF);
//pinMode(LATCHPIN, OUTPUT);
//pinMode(CLOCKPIN, OUTPUT);
//pinMode(DATAPIN, INPUT);
//pinMode(D2, OUTPUT);
//digitalWrite(D2, LOW);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print('.');
}
timeoutNet();
// attach AsyncWebSocket
ws.onEvent(onWsEvent);
server.addHandler(&ws);
// respond to GET requests on URL /heap
server.on("/heap", HTTP_GET, [](AsyncWebServerRequest *r) {
r->send_P(200, "text/html", htmlPage);
});
server.on("/health", HTTP_GET, [](AsyncWebServerRequest *r) {
r->send(200, "text/plain", "ok");
});
server.begin();
}
void loop() {
ws.cleanupClients();
//JsonDocument doc;
static unsigned long last = 0;
if (millis() - last > 3000) {
last = millis();
String lWSData = "{\"pin\":[";
for (int n = 0; n <= 7; n++) {
lWSData = lWSData + random(0,2);
if (n<7){lWSData = lWSData + ",";}
/*
if (switchVar1 & (1 << n)) { // array[0-7]
pin.add(1);
ws.textAll(String(1));
Serial.print("1");
Serial.print("|"); //nclose
} else {
pin.add(0);
ws.textAll(String(0));
Serial.print("0");
Serial.print("|"); //nopen
}
*/
}
lWSData = lWSData+"]}";
Serial.print(lWSData);
ws.textAll(lWSData);
// cheek register СВ4021, contact with rezistors 1,5kOm
//digitalWrite(LATCHPIN, 1);
//delayMicroseconds(20);
//digitalWrite(LATCHPIN, 0);
//--- 1 register СВ4021
//switchVar1 = shiftIn(DATAPIN, CLOCKPIN);
//здесть ненадо дергать сокет, надо собрать 1 пакет данных и отправить
// на стороне клиена расшифровать и расставить по ячейкам.
/*
switchVar1 = 125;
for (int n = 0; n <= 7; n++) {
if (switchVar1 & (1 << n)) { // array[0-7]
ws.textAll(String("P=") + "1"); //nclose
} else {
ws.textAll(String("P=") + "0"); //nopen
}
}
//--- 2 register СВ4021
//switchVar2 = shiftIn(DATAPIN, CLOCKPIN);
switchVar2 = 252;
for (int n = 0; n <= 7; n++) {
if (switchVar2 & (1 << n)) { // array[7-15]
ws.textAll(String("P=") + "1"); //nclose
} else {
ws.textAll(String("P=") + "0"); //nopen
}
}
*/
updateSensors();
//ws.textAll(String("TEMP:") + tempC);
//ws.textAll(String("HUMID:") + byte(humidity));
//ws.textAll(String("SENSOR:") + byte(sensor));
// Write JSON document
//serializeJsonPretty(doc, client);
}
}
void updateSensors() {
sensor = map(analogRead(SENSOR_PIN), 0, 1023, 0, 100);
humidity = random(0,100);
tempC = random(-273,100); // Read temperature as Celsius
tempF = random(459,212); // Read temperature as Fahrenheit (isFahrenheit = true)
/*humidity = dht.readHumidity();
tempC = dht.readTemperature(); // Read temperature as Celsius
tempF = dht.readTemperature(true); // Read temperature as Fahrenheit (isFahrenheit = true)
*/
//if any value is isnan (not a number) then there is an error
if (isnan(humidity) || isnan(tempC) || isnan(tempF)) {
Serial.println("Error reading from the DHT11.");
} else {
String data = "";
data = String(data + sensor);
data = String(data + "|");
data = String(data + byte(humidity));
data = String(data + "|");
data = String(data + tempC);
data = String(data + "|");
data = String(data + tempF);
Serial.println(data); // display the data in the serial monitor
}
}
void onWsEvent(AsyncWebSocket *srv, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len) {
if (type == WS_EVT_CONNECT) {
client->text(ledState ? "ON" : "OFF");
return;
}
if (type == WS_EVT_DATA) {
AwsFrameInfo *info = (AwsFrameInfo *)arg;
if (info->final && info->index == 0 && info->len == len && info->opcode == WS_TEXT) {
String msg;
msg.reserve(len);
for (size_t i = 0; i < len; i++) msg += (char)data[i];
if (msg == "TOGGLE") {
ledState = !ledState;
digitalWrite(LED_PIN, ledState ? LED_ON : LED_OFF);
//ws.textAll(ledState ? "ON" : "OFF");
}
}
}
}
void timeoutNet() { // connection with timeout
int count = 0;
//digitalWrite(LED_BUILTIN, HIGH);
while ((WiFi.status() != WL_CONNECTED) && count < 17) {
Serial.print(".");
count++;
delay(500);
}
//digitalWrite(LED_BUILTIN, LOW);
if (WiFi.status() != WL_CONNECTED) {
Serial.println("");
Serial.print("Failed to connect to ");
while (1)
;
}
Serial.println(ssid);
Serial.print("IP: ");
Serial.println(WiFi.localIP());
}
// 2 регистра сдвига
byte shiftIn(int DATA, int CLK) {
int i;
int temp = 0;
byte pinState;
byte inDATE = 240;
/*
pinMode(CLK, OUTPUT);
pinMode(DATA, INPUT);
for (i = D2; i >= 0; i--) {
digitalWrite(CLK, 0);
delayMicroseconds(2);
temp = digitalRead(DATA);
if (temp) {
pinState = 1;
// несмотря ни на что, задаем биту значение «0»:
inDATE = inDATE | (1 << i);
} else {
pinState = 0;
}
digitalWrite(CLK, 1);
}
*/
return inDATE;
}
результат
в коде много что заккоментировал, думаю разберешься.
и как сказал пиши все в одну JSON строку, можно без библиотеки типа так {“pin”:[0,1,1,0,0,1,0,0], “tem“:25, “hum“: 81} а на стороне клиента разбирай.
если у тебя конечно там сложное дерево то тогда проще библиотекой собирать.
