ZabbixCube/src/main.cpp

244 lines
7.0 KiB
C++

#include <Arduino.h>
#include <Adafruit_SSD1306.h>
#include <ESP8266HTTPClient.h>
#include <ArduinoJson.h>
#include "config.h"
#include "SmartCube/cubeSound.h"
#include "SmartCube/cubeButtons.h"
#include "SmartCube/cubeWifiManager.h"
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
cubeWifiManager cubeWifiManager(display);
unsigned long lastRefresh = 0;
const unsigned long refreshInterval = 60000; // 60 seconds
String lastEventId = "";
String problems[10];
String problemDescriptions;
int problemCount = 0;
int severityCounts[6] = {0};
bool newProblemsDetected = false;
int totalProblems = 0; // Variable to store the total number of active problems
// History buffer for the graph
const int maxHistorySize = 60;
int problemHistory[maxHistorySize] = {0}; // Array to store history
int historyIndex = 0; // Current index for the latest value
int scrollPos = SCREEN_WIDTH; // Global variable to keep track of the scroll position
unsigned long lastScrollTime = 0; // To control the scroll speed
const int scrollDelay = 120; // Delay in milliseconds between scroll updates
void initSystems() {
pinMode(PIN_BTN_L, INPUT);
pinMode(PIN_BTN_M, INPUT);
pinMode(PIN_BTN_R, INPUT);
pinMode(PIN_BUZZER, OUTPUT);
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);
Wire.begin(); // Initialize I2C
Wire.setClock(400000L); // Set I2C to Fast Mode (400 kHz)
display.ssd1306_command(SSD1306_SETCONTRAST);
display.ssd1306_command(200); // Value between 0 and 255
// Initialize the SSD1306 display
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Adjust I2C address if needed
for (;;); // Don't proceed, loop forever
}
// Rotate the display 180 degrees
display.setRotation(2);
// Clear the display buffer
display.clearDisplay();
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(0, 0);
display.display();
}
void fetchActiveProblems() {
WiFiClient client;
HTTPClient http;
http.begin(client, zabbixServer);
http.setTimeout(5000); // 5-second timeout
http.addHeader("Content-Type", "application/json");
// JSON payload
DynamicJsonDocument doc(2048); // Increased to avoid memory issues
doc["jsonrpc"] = "2.0";
doc["method"] = "problem.get";
doc["id"] = 1;
doc["auth"] = zabbixToken;
JsonObject params = doc["params"].to<JsonObject>();
params["output"] = "extend";
params["recent"] = true;
params["sortfield"] = "eventid";
params["sortorder"] = "DESC";
String requestBody;
serializeJson(doc, requestBody);
// POST request
int httpResponseCode = http.POST(requestBody);
if (httpResponseCode > 0) {
String response = http.getString();
// Parse response
DynamicJsonDocument responseDoc(8192); // Increased size to fit more data
DeserializationError error = deserializeJson(responseDoc, response);
if (!error) {
JsonArray result = responseDoc["result"].as<JsonArray>();
// Clear descriptions and severity counts
memset(severityCounts, 0, sizeof(severityCounts));
problemDescriptions = ""; // Reset before appending
totalProblems = result.size(); // Set total problems count
// Store the current totalProblems in the history buffer
problemHistory[historyIndex] = totalProblems;
historyIndex = (historyIndex + 1) % maxHistorySize; // Circular buffer
int newProblemCount = 0;
for (JsonObject problem : result) {
String eventId = problem["eventid"].as<String>();
int severity = problem["severity"].as<int>();
String description = problem["name"].as<String>();
// Check for new problems by comparing event IDs
if (eventId.toInt() > lastEventId.toInt()) {
newProblemsDetected = true;
}
if (severity >= 0 && severity < 5) {
severityCounts[severity]++;
}
problemDescriptions += description + " "; // Append description with space for better display
newProblemCount++;
}
problemCount = newProblemCount;
if (problemCount > 0) {
lastEventId = result[0]["eventid"].as<String>();
}
} else {
beep(1000);
}
} else {
problemDescriptions="Zabbix API error";
}
http.end();
}
void playAlertMelody() {
int toneDuration = 60; // Each tone lasts 150ms
int pauseDuration = 20; // Pause between tones
// Play first tone
tone(PIN_BUZZER, 1500); // 1000 Hz
delay(toneDuration);
noTone(PIN_BUZZER);
delay(pauseDuration);
// Play second tone
tone(PIN_BUZZER, 1200); // 1200 Hz
delay(toneDuration);
noTone(PIN_BUZZER);
delay(pauseDuration);
// Play third tone
tone(PIN_BUZZER, 1500); // 1500 Hz
delay(toneDuration);
noTone(PIN_BUZZER);
}
void displayProblems() {
display.clearDisplay();
display.setTextSize(1);
display.setCursor(0, 0);
display.printf("I:%d W:%d A:%d H:%d D:%d",
severityCounts[1],
severityCounts[2],
severityCounts[3],
severityCounts[4],
severityCounts[5]);
if (is_sound_off) {
display.setCursor(122, 0);
display.print("X");
}
display.drawLine(0, 45, 127, 45, 1); // Line under the graph
display.drawLine(0, 10, 127, 10, 1); // Line under the graph
// Draw the history graph
int graphHeight = 30; // Height of the graph
int graphTop = 15; // Top position of the graph
int graphBottom = graphTop + graphHeight;
int maxProblems = *std::max_element(problemHistory, problemHistory + maxHistorySize); // Find max for scaling
if (maxProblems == 0) maxProblems = 1; // Avoid division by zero
for (int i = 0; i < maxHistorySize - 1; i++) {
int x1 = (i * SCREEN_WIDTH) / maxHistorySize;
int x2 = ((i + 1) * SCREEN_WIDTH) / maxHistorySize;
int y1 = graphBottom - (problemHistory[(historyIndex + i) % maxHistorySize] * graphHeight) / maxProblems;
int y2 = graphBottom - (problemHistory[(historyIndex + i + 1) % maxHistorySize] * graphHeight) / maxProblems;
display.drawLine(x1, y1, x2, y2, 1); // Draw line between points
}
// Scroll text below the graph
int stateWidth = strlen(problemDescriptions.c_str()) * 12;
if (!is_display_off) {
if (millis() - lastScrollTime > scrollDelay) {
scrollPos -= 11;
lastScrollTime = millis();
if (scrollPos < -stateWidth) {
scrollPos = SCREEN_WIDTH;
}
}
}
display.setTextSize(2);
display.setCursor(scrollPos, 48);
display.print(problemDescriptions);
display.setTextSize(1);
display.fillRect(112,35,16,11,0);
display.drawRect(112,35,16,11,1);
display.setCursor(113,37);
display.print(totalProblems);
display.display();
}
void setup() {
initSystems();
cubeWifiManager.start();
fetchActiveProblems();
}
void loop() {
unsigned long currentMillis = millis();
cubeButtonHandler();
if (!is_display_off && currentMillis - lastRefresh >= refreshInterval) {
lastRefresh = currentMillis;
fetchActiveProblems();
}
displayProblems();
if (newProblemsDetected && !is_sound_off) {
playAlertMelody();
newProblemsDetected = false;
}
}