// Extract the payload
let payload = msg.payload;
msg.container = "S5";
// Initialize the result object
let result = {
analog_sensors: {},
digital_inputs: {}
};
// Regex patterns to match the sensor readings
let analogSensorPattern = /([^<]+)<\/td> ([^<]+)<\/td><\/tr>/g;
let digitalSensorPattern = / ([^<]+)<\/td> ([^<]+)<\/td><\/tr>/g;
// Extract analog sensor readings
let match;
while (match = analogSensorPattern.exec(payload)) {
let sensorName = match[1].trim();
let sensorValue = match[2].trim();
result.analog_sensors[sensorName] = sensorValue;
}
// Extract digital input readings
while (match = digitalSensorPattern.exec(payload)) {
let sensorName = match[1].trim();
let sensorValue = match[2].trim();
result.digital_inputs[sensorName] = sensorValue;
}
// Return the result as a JSON object
msg.payload = result;
return msg;
// Extract the payload (HTML content)
let html = msg.payload;
// Initialize a variable to store the heater status
let heaterStatus = "Unknown";
// Use a regular expression to find the heater status
let statusMatch = html.match(/Status: (ON|OFF)/i);
if (statusMatch) {
// Extract the status (ON or OFF) from the match
heaterStatus = statusMatch[2];
}
// Set the heater status as the new payload
msg.payload = heaterStatus;
// Return the modified message
return msg;
// Initialize an empty array to store digital sensor data
let digitalSensorsArray = [];
// Extract the digital_inputs object from the payload
let digitalInputs = msg.payload.digital_inputs;
// Loop through each key-value pair in the digital_inputs object
for (let [sensorName, sensorValue] of Object.entries(digitalInputs)) {
// Push each sensor's name and value as an object to the array
digitalSensorsArray.push({
name: sensorName,
value: sensorValue
});
}
// Set the output message payload to the array of digital sensors
msg.payload = digitalSensorsArray;
// Return the modified message
return msg;
// Extract the digital sensors array from the incoming message payload
let digitalSensorsArray = msg.payload;
// Initialize an empty array to store sensors with value "0"
let sensorsWithZeroValue = [];
// Loop through each sensor in the array
for (let sensor of digitalSensorsArray) {
// Check if the sensor's name starts with "Waveguide Position"
if (!sensor.name.startsWith("Waveguide Position")) {
// Check if the sensor's value is "0"
if (sensor.value === "0") {
// Add the sensor to the array of sensors with value "0"
sensorsWithZeroValue.push(sensor);
}
}
}
// Check if there are any sensors with value "0"
if (sensorsWithZeroValue.length > 0) {
// Set the message payload to the array of sensors with value "0"
msg.payload = sensorsWithZeroValue;
// Return the message to the next node
return msg;
} else {
// If no sensors have value "0", return null (which means the message is discarded)
return null;
}
// Access the temperature value from the JSON object
msg.payload = parseInt(msg.payload.analog_sensors["Temperature"]);
msg.name = "Temperature"
msg.container = "S5";
// Return the modified message
return msg;
// Access the temperature value from the JSON object
msg.payload = parseInt(msg.payload.analog_sensors["Humidity"]);
msg.name = "Humidity";
msg.container = "S5";
// Return the modified message
return msg;
// Access the temperature value from the JSON object
msg.payload = msg.payload.analog_sensors["Electric Current"];
msg.payload = parseFloat(msg.payload.match(/[\d.]+/)[0]);
msg.name = "Electric Current";
msg.container = "S5";
// Return the modified message
return msg;
msg.topic = `INSERT INTO \`S5_Temperature\` (\`DATE\`, \`VALUE\`) VALUES (now(), '${msg.payload}');`;
return msg;
//pierwszy
msg.url = "http:///graphs/S5_Temperature_1d.png";
return msg;
//drugi
msg.url = "http:///graphs/S5_Current_1d.png";
return msg;
//trzeci
msg.url = "http:///graphs/S5_Humidity_1d.png";
return msg;
==== Wyjaśnienie zasady działania węzłów ====
-
Węzeł: Extract Data from Web
Węzeł odpowiedzialny za przetwarzanie danych HTML pobranych ze strony WWW. W pierwszej kolejności przypisuje zawartość ''%%msg.payload%%'' do zmiennej ''%%payload%%'' oraz ustawia nazwę kontenera jako ''%%S5%%'' (''%%msg.container%%''). Następnie tworzy pusty obiekt ''%%result%%'', zawierający dwie sekcje: ''%%analog_sensors%%'' oraz ''%%digital_inputs%%''.
Za pomocą wyrażeń regularnych\\
''%%/ ([^<]+)<\/td> ([^<]+)<\/td><\/tr>/g%%''\\
przeszukuje dane HTML w celu wyodrębnienia nazw i wartości sensorów analogowych i cyfrowych. W każdej pętli ''%%while%%'', odnalezione dane przypisywane są do odpowiednich pól w obiekcie ''%%result%%''.
Na końcu wynikowy obiekt JSON jest przypisywany do ''%%msg.payload%%'' i przekazywany dalej.
-
Węzeł: Extract heater status
Węzeł służy do odczytu stanu grzejnika na podstawie treści HTML przekazanej w ''%%msg.payload%%''. Za pomocą wyrażenia regularnego ''%%/%%''\\
''%%Status: (ON|OFF)/i%%'' wyszukiwany jest fragment HTML zawierający informację o stanie urządzenia.
Jeśli dopasowanie zakończy się powodzeniem (''%%if (statusMatch)%%''), z drugiego elementu tablicy wynikowej ''%%statusMatch[2]%%'' pobierany jest status grzejnika (np. ''%%ON%%'' lub ''%%OFF%%''). Wartość ta przypisywana jest do ''%%msg.payload%%'' i przekazywana dalej w przepływie.
-
Węzeł: Extract Digital in simpler array
Węzeł przekształca dane wejściowe z obiektu ''%%msg.payload.digital_inputs%%'' na prostszą formę — tablicę obiektów. Na początku tworzona jest pusta tablica ''%%digitalSensorsArray%%'', do której kolejno dodawane są obiekty zawierające nazwę i wartość każdego czujnika cyfrowego (''%%name%%'', ''%%value%%'').
Dane są pozyskiwane za pomocą pętli ''%%for (let [sensorName, sensorValue] of Object.entries(...))%%'', a wynik przypisywany do ''%%msg.payload%%'' jako nowa, uproszczona struktura danych.
-
Węzeł: check status
Węzeł analizuje dane wejściowe zawarte w ''%%msg.payload%%'', które stanowią tablicę czujników cyfrowych. Dla każdego czujnika wykonywana jest kontrola — jeśli jego nazwa nie zaczyna się od ''%%"Waveguide Position"%%'' oraz jego wartość wynosi ''%%"0"%%'', to czujnik zostaje dodany do nowej tablicy ''%%sensorsWithZeroValue%%''.
Jeśli po zakończeniu pętli tablica zawiera jakiekolwiek elementy, zostaje ona ustawiona jako nowe ''%%msg.payload%%'' i przekazana dalej. W przeciwnym przypadku węzeł zwraca ''%%null%%'', co powoduje przerwanie dalszego przetwarzania wiadomości.
-
Węzeł: Extract Temperature
Węzeł pobiera wartość temperatury z pola\\
''%%analog_sensors["Temperature"]%%'' znajdującego się w ''%%msg.payload%%'', a następnie konwertuje ją do liczby całkowitej za pomocą ''%%parseInt(...)%%'', przypisując wynik z powrotem do ''%%msg.payload%%''. Ustawia również identyfikatory ''%%msg.name%%'' oraz ''%%msg.container%%'' odpowiednio na ''%%"Temperature"%%'' i ''%%"S5"%%''.
-
Węzeł: Extract Humidity
Analogicznie do poprzedniego węzła, pobiera wartość wilgotności z\\
''%%analog_sensors["Humidity"]%%'', konwertuje ją na liczbę całkowitą funkcją ''%%parseInt(...)%%'' i przypisuje do ''%%msg.payload%%''. Ustawia także nazwę parametru i kontenera w ''%%msg.name%%'' oraz ''%%msg.container%%''.
-
Węzeł: Extract Current
Węzeł odpowiedzialny za ekstrakcję wartości natężenia prądu z pola\\
''%%analog_sensors["Electric Current"]%%''. Używa wyrażenia regularnego\\
''%%msg.payload.match(/[.̣]+/)%%'' do wyłuskania liczby zmiennoprzecinkowej z tekstu, a następnie przekształca ją do typu ''%%float%%''. Dodaje również pola opisujące nazwę parametru i kontener.
-
Węzeł: make SQL query
Generuje zapytanie SQL wstawiające wartość pomiaru temperatury do tabeli ''%%S5_Temperature%%'' z aktualnym znacznikiem czasu. Tworzy pole ''%%msg.topic%%'' zawierające zapytanie w formacie\\
''%%INSERT INTO ... VALUES (now(), '${msg.payload}')%%''.
-
Węzły: set URL
Każdy z węzłów ustawia odpowiedni adres URL wykresu parametru w polu ''%%msg.url%%'':
* Pierwszy węzeł: ''%%S5_Temperature_1d.png%%''
* Drugi węzeł: ''%%S5_Current_1d.png%%''
* Trzeci węzeł: ''%%S5_Humidity_1d.png%%''
Adresy odnoszą się do zasobów graficznych generowanych przez zewnętrzny serwer WWW.
===== Bloki: Thresholds i CATCH ERRORS =====
{{2.png}}
Widok bloków z aplikacji Node-RED
==== Listingi poszczególnych węzłów funkcyjnych ====
msg.lowerThreshold = global.get("temperatureLowerThold","file");
msg.upperThreshold = global.get("temperatureUpperThold","file");
return msg;
let value = msg.payload; // The incoming numeric value
let name = msg.name; // Variable name
let lowerThreshold = msg.lowerThreshold; // Lower boundary
let upperThreshold = msg.upperThreshold; // Upper boundary
let container = msg.container; // Name of the container
msg.url = "http://api.ttcomm.net/graphs/S5_Temperature_1d.png";
msg.value = value; //used for extracting it for email
if (value < lowerThreshold || value > upperThreshold) {
msg.topic = `INSERT INTO \`thold_log\` (\`TIME\`, \`CONTAINER\`, \`LOG\`)
VALUES (NOW(), '${container}',
'Parameter ${name} in container ${container} has a value of ${value}, which is outside the set boundaries (${lowerThreshold} - ${upperThreshold}).');`;
return msg; // Send the message to the next node
} else {
return null;
}
==== Wyjaśnienie zasady działania węzłów ====
-
Węzeł: setValuesForThresholdNode
Węzeł ten pobiera z pamięci globalnej zdefiniowane progi temperatury: dolny ''%%temperatureLowerThold%%'' oraz górny ''%%temperatureUpperThold%%'', zapisane w pliku konfiguracyjnym (drugi parametr: ''%%"file"%%''). Ustawia je w wiadomości jako pola ''%%msg.lowerThreshold%%'' oraz ''%%msg.upperThreshold%%'', umożliwiając ich dalsze użycie w logice porównawczej.
-
Węzeł: thold
Węzeł służy do porównania wartości pomiaru z zadanymi progami. Na podstawie pól ''%%msg.payload%%'' (wartość), ''%%msg.lowerThreshold%%'', ''%%msg.upperThreshold%%'', ''%%msg.name%%'' oraz ''%%msg.container%%'' wykonywana jest kontrola, czy wartość wychodzi poza zadane granice.
Jeśli tak, to generowane jest zapytanie SQL (''%%msg.topic%%'') dodające rekord do tabeli ''%%thold_log%%'', zawierający czas, nazwę kontenera oraz opis przekroczenia. Dodatkowo przypisywane są pola ''%%msg.url%%'' (link do wykresu) oraz ''%%msg.value%%'' (wykorzystywana np. do wiadomości e-mail). Jeśli wartość mieści się w dopuszczalnych granicach, węzeł zwraca ''%%null%%'', zatrzymując dalszy przepływ wiadomości.
===== Blok: Show logs in table =====
{{3.png}}
Widok bloków z aplikacji Node-RED
==== Listingi poszczególnych węzłów funkcyjnych ====
msg.topic = `SELECT * FROM thold_log;`;
return msg;
==== Zasada działania ====
Tutaj zasada działania jest bardzo prosta pobieramy wszystko co jest w tabeli ''%%thold_log%%'' a następnie wyświetlamy to w interfejsie w formie tabeli.
===== Blok: Send Numerical notificaiton from numerical sensors =====
{{4.png}}
Widok bloków z aplikacji Node-RED
==== Listingi poszczególnych węzłów funkcyjnych ====
msg.from = "node-red@ttcomm.net"
msg.topic = `Alert: ${msg.container} ${msg.name} is outside thresholds`;
msg.payload = `Parameter ${msg.name} in container ${msg.container} has a value of ${msg.value}, which is outside the set boundaries (${msg.lowerThreshold} - ${msg.upperThreshold})
Click here to view graph`;
return msg;;
==== Zasada działania ====
Tutaj pobieramy z obiektu ''%%msg%%'' potrzebne parametry żeby utworzyć wiadomośc email aby następnie wysłać ją do odpowiednich użytkowników
===== Blok: Thold settings =====
{{5.png}}
Widok bloków z aplikacji Node-RED
==== Listingi poszczególnych węzłów funkcyjnych ====
//bloki lower
global.set("humidityLowerThold", msg.payload, "file");
//bloki upper
global.set("currentUpperThold", msg.payload, "file");
==== Zasada działania ====
Tutaj ustawiamy wartości globalne dla poszczególnych thresholdów. Są one nastepnie wykorzystywane w poprzednich omawianych tutaj przepływach.
===== Blok: Send email notification from digital sensors =====
{{6.png}}
Widok bloków z aplikacji Node-RED
==== Listingi poszczególnych węzłów funkcyjnych ====
msg.from = "node-red@ttcomm.net"
msg.topic = `Alert: ${msg.container} digital sensors changed status`;
msg.payload = `Sensor in container ${msg.container} status: ${msg.sensorStatusString}`;
return msg;
==== Zasada działania ====
Ten blok jest potrzebny z racji trochę innej struktury maili dla sensorów z wartościami numerycznymi.
===== Blok: Python graphing =====
{{7.png}}
Widok bloków z aplikacji Node-RED
==== Zasada działania ====
Przedstawiony przepływ Node-RED realizuje automatyczną oraz ręczną generację wykresów na podstawie skryptów Pythona. Cztery wyzwalacze czasowe (co 5 minut, 8 godzin, 48 godzin, oraz 500 godzin) inicjują wykonanie odpowiednich skryptów generujących wykresy dla okresów: 1, 7, 30 i 365 dni. Dodatkowo, zastosowany został przycisk umożliwiający ręczne wygenerowanie wszystkich wykresów jednocześnie oraz kolejny przycisk służący do powrotu do domyślnego widoku wykresów. Wyniki uruchamiania skryptów prezentowane są użytkownikowi na pulpicie Node-RED poprzez elementy UI, wyświetlające logi z wykonania skryptów oraz powiadomienia ("toast"). Całość interfejsu dopełnia element typu iframe, w którym użytkownik może wygodnie przeglądać wygenerowane wykresy.
====== Skrypt w Pythonie do generowania grafów ======
Skrypt odpowiedzialny jest za automatyczne generowanie wykresów parametrów środowiskowych takich jak temperatura, wilgotność oraz pobór prądu na podstawie danych zgromadzonych w bazie MySQL. Dane te są następnie przetwarzane i wizualizowane w formie wykresów PNG, które mogą być publikowane w sieci lokalnej lub w przeglądarce użytkownika końcowego.
{{graph.png}}
Przykład grafu wygenerowanego przez skrypt
===== Opis działania skryptu =====
Skrypt rozpoczyna działanie od zaimportowania niezbędnych bibliotek: ''%%pymysql%%'' do komunikacji z bazą danych, ''%%matplotlib.pyplot%%'' do generowania wykresów, ''%%pandas%%'' do analizy danych oraz ''%%datetime%%'' do obsługi czasu (''%%linia 1–5%%'').
Funkcja ''%%plot_1d_graph(table_name)%%'' przyjmuje jako argument nazwę tabeli z bazy danych, z której zostaną pobrane dane (''%%linia 7%%''). Następnie nawiązywane jest połączenie z bazą danych MySQL (''%%linia 9–13%%''), a dane z kolumn ''%%DATE%%'' oraz ''%%VALUE%%'' są pobierane do ramki danych ''%%DataFrame%%'' przy użyciu zapytania SQL (''%%linia 16%%'').
Po pobraniu danych połączenie zostaje zamknięte (''%%linia 19%%''), a kolumna ''%%DATE%%'' jest konwertowana do typu ''%%datetime%%'' (''%%linia 22%%''), co umożliwia filtrowanie danych w zadanym zakresie czasu.
Zakres czasowy ustalany jest na ostatnie 24 godziny, co realizuje fragment:
start_date = datetime.now() - timedelta(days=1)
filtered_df = df[df['DATE'] >= start_date]
Następnie, za pomocą biblioteki ''%%matplotlib%%'', generowany jest wykres typu liniowego (''%%linia 27–31%%''). Na wykresie umieszczane są podpisy osi oraz tytuł wykresu, który zawiera nazwę tabeli.
Wygenerowany wykres jest zapisywany jako plik PNG w katalogu ''%%/var/www/html/graphs/%%'' pod nazwą odpowiadającą nazwie tabeli z przyrostkiem ''%%_1d%%'' (''%%linia 34%%'').
Na końcu, skrypt wywołuje funkcję ''%%plot_1d_graph%%'' trzykrotnie dla różnych tabel:
* ''%%S5_Temperature%%''
* ''%%S5_Humidity%%''
* ''%%S5_Current%%''
Każde z tych wywołań skutkuje wygenerowaniem osobnego wykresu z ostatnich 24 godzin dla danego parametru.
import pymysql
import matplotlib.pyplot as plt
import pandas as pd
from datetime import datetime, timedelta
def plot_1d_graph(table_name):
# Establish connection to the MySQL database
conn = pymysql.connect(
host='localhost', # Your MySQL host
user='administrator', # Your MySQL username
password='PASS',# Your MySQL password
database='mcTTcomm' # Your database name
)
# Fetch data from the specified table
query = f"SELECT DATE, VALUE FROM {table_name}"
df = pd.read_sql(query, conn)
# Close the connection
conn.close()
# Convert 'DATE' column to datetime format
df['DATE'] = pd.to_datetime(df['DATE'])
# Define time range for 1 day
start_date = datetime.now() - timedelta(days=1)
filtered_df = df[df['DATE'] >= start_date]
# Plotting
plt.figure(figsize=(10, 6))
plt.plot(filtered_df['DATE'], filtered_df['VALUE'], linestyle='-')
plt.title(f'{table_name} Measurements Over Last 1 Day')
plt.xlabel('Date')
plt.ylabel('Value')
plt.grid(True);
# Save the plot as a PNG file
output_path = f'/var/www/html/graphs/{table_name}_1d.png'
plt.savefig(output_path)
plt.close()
print(f"1-day graph saved to {output_path}")
# Example usage:
plot_1d_graph('S5_Temperature')
plot_1d_graph('S5_Humidity')
plot_1d_graph('S5_Current')
====== Interfejs Graficzny ======
{{gui1.png}}
Główna strona interfejsu
Główna strona aplikacji prezentuje kluczowe informacje w czytelnej formie graficznej. Znajdują się tutaj trzy wskaźniki wskazówkowe (gauges), pokazujące odczyty bieżących parametrów środowiskowych: temperatury, wilgotności oraz natężenia prądu elektrycznego. Dodatkowo, użytkownik posiada możliwość manualnej kontroli urządzenia grzewczego, które można załączać lub wyłączać z częstotliwością maksymalnie raz na 5 minut. Po prawej stronie znajduje się przestrzeń do wyświetlania aktualnych wykresów przedstawiających historię pomiarów dla ostatniego dnia.
{{gui2.png}}
Tabela z logami
Zakładka tabeli z logami wyświetla szczegółowe informacje o zdarzeniach systemowych. Każdy rekord zawiera znacznik czasowy konkretnego zdarzenia, identyfikator kontenera, którego dotyczy zdarzenie oraz treść powiadomienia. Logi informują przede wszystkim o przekroczeniach zdefiniowanych progów parametrów środowiskowych (np. temperatura poza dopuszczalnym zakresem).
{{gui3.png}}
Ustawienia progów powiadomień
Interfejs ustawień pozwala użytkownikowi na konfigurację progów upozorowaniowych dla poszczególnych parametrów środowiskowych. Parametry te to górne i dolne limity temperatury, wilgotności oraz natężenia prądu elektrycznego. Po lewej stronie widoczna jest aktualna konfiguracja, natomiast po prawej stronie użytkownik może intuicyjnie dostosowywać te wartości przy użyciu suwaków.
{{gui4.png}}
Interfejs do przeglądania grafów
Sekcja przeglądania wykresów pozwala na generowanie oraz wizualizację wcześniej zapisanych plików graficznych prezentujących historyczne pomiary parametrów. Po lewej stronie widoczne są logi informujące użytkownika o statusie generacji wykresów wraz z możliwością ich wyczyszczenia. Po prawej stronie znajduje się widok katalogu z wygenerowanymi wykresami, posortowanymi według parametrów oraz zakresów czasowych (np. 1 dzień, 7 dni, 30 dni oraz 1 rok). Użytkownik może również ręcznie wymusić wygenerowanie wszystkich wykresów za pomocą dedykowanego przycisku.
====== Spisy ======
===== Wykaz załączników =====
- Skrypt bazy danych oraz dane które system zebrał {{ :projekty:db.zip |}}
- Kod dla platformy Arduino MEGA
#include
#include
#include
#include
#include
#include
#include
AVT5636 myBoard;
Servo myServo;
SimpleDHT11 dht11;
byte mac[] = {
0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 80, 53);
// Initialize the Ethernet server library
EthernetServer server(8080);
float temperature;
float humidity;
int term2=0;
int term3=0;
int term4=0;
int term5=0;
uint32_t prevMillis = millis();
void setup() {
pinMode(22, INPUT_PULLUP);
pinMode(24, INPUT_PULLUP);
pinMode(26, INPUT_PULLUP);
pinMode(28, INPUT_PULLUP);
pinMode(30, INPUT_PULLUP);
myBoard.init();
myServo.attach(PULSE2_PIN);
//delay(3000);
//Serial.begin(9600);
//while (!Serial) {
// ; // wait for serial port to connect. Needed for native USB port only
//}
Ethernet.begin(mac, ip);
server.begin();
//Serial.print("server is at ");
//Serial.println(Ethernet.localIP());
}
String HTTP_req;
bool LED_status4 = 0;
bool LED_status3 = 0;
bool LED_status2 = 0;
int IntTemperature;
int IntHumidity;
unsigned long previousMillis = 0;
float CurrentSensor = 0;
void loop() {
CurrentSensor = ((5.0/1024.0)*analogRead(10))*10;
//Serial.println(CurrentSensor);
LED_status4 = 0;
LED_status3 = 0;
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= 60000) {
previousMillis = currentMillis;
delay(2000);
byte temperature = 0;
byte humidity = 0;
byte err = SimpleDHTErrSuccess;
if ((err = dht11.read(31, &temperature, &humidity, NULL)) != SimpleDHTErrSuccess) {
//Serial.print("Failed to read from DHT sensor, err=");
//Serial.println(err);
return;
}
IntTemperature = temperature;
IntHumidity = humidity;
term2 = temperature;
term3 = humidity;
}
term4 = 444;
term5 = 555;
EthernetClient a = server.available();
serveWebsite(a);
}
EthernetClient serveWebsite(EthernetClient client){
if (client) {
//Serial.println("new client");
bool currentLineIsBlank = true;
while (client.connected()) {
//Serial.println("test1");
if (client.available()) {
//Serial.println("test2");
char c = client.read();
//Serial.write(c);
HTTP_req += c;
if (c == '\n' && currentLineIsBlank) {
//Serial.println("test3");
if (HTTP_req.indexOf("LED4=On") > -1) { LED_status4 = 1; }
if (HTTP_req.indexOf("LED4=Off") > -1) { LED_status4 = 0; }
if (HTTP_req.indexOf("LED3=On") > -1) { LED_status3 = 1; }
if (HTTP_req.indexOf("LED3=Off") > -1) { LED_status3 = 0; }
if (HTTP_req.indexOf("LED2=On") > -1) { LED_status2 = 1; }
if (HTTP_req.indexOf("LED2=Off") > -1) { LED_status2 = 0; }
client.println(F("HTTP/1.1 200 OK"));
client.println("Content-Type: text/html");
client.println("Connection: close");
//client.println("Refresh: 10; URL=/");
client.println();
client.println("");
client.println("");
client.println("");
client.println("");
// client.println("");
client.println("");
client.println("");
client.println("");
client.println("System Pomiarowo-Kontrolny TTCOMM Sp.z.o.o.
");
client.println("Opracowano przez: Kacper Ostrowski
");
client.println("Wersja z dnia: 11.06.2024
");
client.println("Analog Sensor Readings
");
client.println("");
client.println("Sensor Value ");
client.println("Temperature " + String(IntTemperature) + " C ");
client.println("Humidity " + String(IntHumidity) + " % ");
client.println("Electric Current "+String(CurrentSensor)+" A ");
client.println("
");
client.println("Digital Input Readings
");
client.println("");
client.println("Sensor Value ");
client.print("Door Open/Closed ");
client.print(digitalRead(22));
client.println(" ");
client.print("Flood sensor ");
client.print(digitalRead(24));
client.println(" ");
client.print("Waveguide Position 1 ");
client.print(digitalRead(26));
client.println(" ");
client.print("Waveguide Position 2 ");
client.print(digitalRead(28));
client.println(" ");
client.print("Waveguide Power Supply ");
client.print(digitalRead(30));
client.println(" ");
client.println("
");
client.println("Control Buttons
");
client.println("Override Control Buttons:");
client.println("");
client.println("");
client.println("");
client.println("");
HTTP_req = "";
break;
}
if (c == '\n') {
currentLineIsBlank = true;
} else if (c != '\r') {
currentLineIsBlank = false;
}
}
}
client.stop();
//Serial.println("client disconnected");
}
}