diff --git a/README.md b/README.md index 7d8b1f9..0033481 100644 --- a/README.md +++ b/README.md @@ -1,92 +1,170 @@ -# 🛡️ Netgotchi +# 🛡️ Netgotchi - ESP32-C6 + ST7789 1.47" LCD Fork ![Netgotchi Image](https://github.com/MXZZ/Netgotchi/assets/3322271/947416e6-c088-4167-ba62-e69a6d1170ce) > Netgotchi: Your network's loyal guardian! 🐾 +This is a **community fork** of the original Netgotchi project, specifically adapted for **Waveshare ESP32-C6-LCD-1.47"** with **ST7789 display (172×320)** using Arduino IDE. + A small arduino .ino script with some great functions to detect intruders or breaches in the network, it pings periodically the network and reports if any new device. It also has a rudimental "Honeypot" functionality with a rudimental exposed service, once someone reaches the honeypot it will trigger an alarm. Please contribute to the repository via pull requests! Tested with Nmap, service scan / intense scan will trigger the alert. +## 🔥 This Fork Features +- ✅ **ESP32-C6** compatibility with Arduino IDE +- ✅ **ST7789 1.47" TFT LCD** (172×320) support replacing OLED +- ✅ **ESP-NOW** API updated for ESP32 v3.x (IDF 5.x) +- ✅ **FTP disabled** with stub implementation (no SD_MMC dependency) +- ✅ **Deauther module excluded** (ESP8266 only) with safe stubs +- ✅ Various fixes: pin definitions, display initialization, WebUI compatibility + +## ⚠️ AI Development Disclaimer +**All code modifications and adaptations in this fork were developed with assistance from ChatGPT-5 Extended Thinking**. While the code has been tested and works, there may be more optimal approaches or improvements possible. We encourage the community to: +- **Open issues** if you find bugs or have suggestions +- **Submit pull requests** with optimizations or improvements +- **Share better implementation approaches** for any of the adaptations made + +Your expertise and contributions are welcome to make this fork even better! + ## 🌟 Features - 🔍 Periodic network scanning - 🍯 Built-in "Honeypot" functionality - 🚨 Intrusion detection and alerting - 🖥️ Support for multiple OLED display types -- 🔄 Supports both ESP8266 and ESP32 +- 🔄 Original supports ESP8266 and ESP32 (this fork specialized for ESP32-C6) -![Netgotchi Screen 1](https://github.com/MXZZ/Netgotchi/assets/3322271/cf8d7fec-7b33-4f14-9992-8cb4806633f2) ![Netgotchi Screen 2](https://github.com/MXZZ/Netgotchi/assets/3322271/68f4fe6c-9172-422b-ba39-ee901c098840) +## 📸 ESP32-C6 Fork in Action -## 🛒 Get an Official Build and support the development ❤ +### Main Interface with Network Status +![Netgotchi Main Screen](images/fork/screen1.jpg) +*Shows the main interface with IP address, uptime, network hosts count, and honeypot status - all displayed on the beautiful ST7789 color display* -Support the development by getting an official Netgotchi build: +### Network Monitoring Dashboard +![Network Monitoring](images/fork/screen2.jpg) +*Network scanning visualization showing detected devices and connectivity status in real-time* -- [Tindie](https://www.tindie.com/products/ollestore/negotchi-network-security-scanner/) -- [Etsy](https://olleadventures.etsy.com/listing/1752764124) +### Netgotchi Face Animation +![Netgotchi Face](images/fork/screen3.jpg) +*The iconic Netgotchi face with scan mode indicator - now in full color on the 1.47" TFT display* -## New! -![Netgotchi CARD](https://www.tindie.com/products/ollestore/netgotchi-card-7mm-business-card-size/) - - ![immagine](https://github.com/user-attachments/assets/420866cf-a5f5-4996-8471-86070394fe3f) +### RGB LED Strip Integration +![RGB Working](images/fork/rgb-working.jpg) +*Showcasing the RGB LED strip integration with the 3D printed case - adding visual network status indicators* +### Original Project Screenshots (for comparison) +![Original Netgotchi OLED](https://github.com/MXZZ/Netgotchi/assets/3322271/cf8d7fec-7b33-4f14-9992-8cb4806633f2) ![Original Interface](https://github.com/MXZZ/Netgotchi/assets/3322271/68f4fe6c-9172-422b-ba39-ee901c098840) +*Original project with OLED display - compare with the colorful ST7789 version above!* +## 🛒 Support Original Development ❤ -### Note : for security purpose make sure you buying from from official the link above, you will receive the latest version of this repository, without any modification. +**This is a community fork. Please support the original creator [MXZZ](https://github.com/MXZZ)**: -PRO version & Prototypes +- [Original Netgotchi on Tindie](https://www.tindie.com/products/ollestore/negotchi-network-security-scanner/) +- [Original Netgotchi on Etsy](https://olleadventures.etsy.com/listing/1752764124) +### Original Netgotchi PRO +The original project offers a PRO version with keypad interface, multiple modes (TEXTgotchi, CTRLgotchi), and audio alerts. **This fork focuses only on ESP32-C6 + ST7789 compatibility** and doesn't include the PRO features. + -![IMG_20240829_1519522](https://github.com/user-attachments/assets/b584b5f6-9727-46fc-9bce-9cad7c8529e4) -Netgotchi Pro version : -Pro version has a keypad to access the settings, change mode like chat-device ( TEXTgotchi ) or gpio remote controller ( CTRLgotchi ) , from the device itself without re-flashing settings and a small buzzer for sound alerts! -- [Netgotchi PRO on Tindie](https://www.tindie.com/products/35655/) -- [Netgotchi PRO on Etsy](https://olleadventures.etsy.com/listing/1771783598) - +## 🛠️ Requirements (ESP32-C6 Fork) +### Hardware +- **Waveshare ESP32-C6-LCD-1.47"** board +- **ST7789 1.47" TFT LCD** (172×320 resolution) +- USB-C cable for programming +- Optional: **3D Printed Case** - [ESP32-C6 Display Case on MakerWorld](https://makerworld.com/it/models/1628925-esp32-c6-display-case) -## 🛠️ Requirements +### Software +- **Arduino IDE** with ESP32 Core v3.x +- **Board**: ESP32C6 Dev Module -- ESP8266 or ESP32 +### Libraries (Install via Library Manager) +- **Adafruit GFX Library** +- **Adafruit ST7735 and ST7789 Library** +- **WiFiManager** (by tzapu) +- **Button2** (by Lennart Hennigs) +- **NTPClient** +- **ESP32Ping** (optional, for min/avg/max ping stats) + +### Original Requirements (for reference) +- ESP8266 or ESP32 (standard versions) - OLED display (SSD1306, SH1106, or SSD1305) -- USB cable - Optional: 3D printed case ([Community case for Wemos D1](https://www.printables.com/model/510481-terminal-for-ssd1306-096-oled-and-wemos-d1-mini)) ## 📊 Wiring Diagram -ESP8266 + +### ESP32-C6 + ST7789 Pin Configuration (This Fork) + +| Signal | GPIO | Function | +|:-------|:----:|:---------| +| MOSI | 6 | SPI Data | +| SCLK | 7 | SPI Clock | +| CS | 14 | Chip Select | +| DC | 15 | Data/Command | +| RST | 21 | Reset | +| BL | 22 | Backlight | + +> **Note**: No MISO pin needed for ST7789 display. + +### Original Wiring Diagrams (for reference) + +**ESP8266** ![Netgotchi Diagram](https://github.com/MXZZ/Netgotchi/assets/3322271/54fb9be5-4fe4-4ff3-b24a-f2a05287d893) -ESP32 + +**ESP32** ![esp32](https://github.com/user-attachments/assets/cc486dfd-fdb6-468b-a158-2e0a78891ac4) ## 📚 Libraries +### ESP32-C6 Fork Libraries +- **ESP32 Core v3.x** (required for ESP32-C6 support) +- **Adafruit GFX Library** +- **Adafruit ST7735 and ST7789 Library** (replaces OLED libraries) +- **WiFiManager** (tzapu) +- **Button2** (Lennart Hennigs) +- **NTPClient** +- **ESP32Ping** (optional, for enhanced ping statistics) + +> **Note**: FTP functionality is disabled in this fork with stub implementation (no SD_MMC dependency required) + +### Original Libraries (for reference) - ESP8266/ESP32 core libraries -- Modified FTP Server library (ESP8266FtpServer or ESP32FtpServer) -- you need to install the one provided in the "/libraries" folder in this repo -- Adafruit_GFX -- Adafruit_SSD1306, Adafruit_SH110X, or Adafruit_SSD1305 (based on your OLED type) +- Modified FTP Server library (ESP8266FtpServer or ESP32FtpServer) +- Adafruit_SSD1306, Adafruit_SH110X, or Adafruit_SSD1305 (OLED displays) - ESPping -- NTPClient -- WiFiManager -- Button2 -## 🚀 How to Use +## 🚀 How to Use (ESP32-C6 Fork) -1. Open the `.ino` file in the Arduino IDE, make sure you have all files open like the image below : - ![immagine](https://github.com/user-attachments/assets/552f5d19-d55d-4d47-9ef4-f200438421e6) +### Setup Instructions -2. Select your OLED display type by setting the appropriate flag to 1 (e.g., `#define oled_type_ssd1306 1`).![immagine](https://github.com/user-attachments/assets/c1fef59b-e22a-4555-94cb-8ef26b71e756) +1. **Install ESP32 Board Package**: Make sure you have ESP32 Arduino Core v3.x installed +2. **Install Required Libraries**: Use Arduino Library Manager to install all libraries listed above +3. **Download Fork Files**: Clone or download this fork repository +4. **Open in Arduino IDE**: Open `netgotchi.ino` and ensure all accompanying files are loaded +5. **Select Board**: Choose "ESP32C6 Dev Module" from the board menu +6. **Verify Pins**: The fork automatically configures ST7789 pins (no manual configuration needed) +7. **Upload**: Compile and upload to your ESP32-C6 board -3. Install the required libraries via the Arduino Library Manager. -4. Select your board (ESP8266 or ESP32) in the Arduino IDE. -5. Flash the code to your board. -6. On the first boot, Netgotchi will create a WiFi hotspot named "AutoConnectAP" for you to set up your WiFi credentials. -7. Once connected, Netgotchi will start guarding your network! +### Added Files (specific to this fork) +- `globals.h` - Unified include for all .ino files +- `pins_local.h` - Pin definitions (BTN_A/B/LEFT/RIGHT, BUZZER_PIN, etc.) +- `espnow.h` - ESP-NOW compatibility wrapper for ESP32 v3.x +- `ESPping.h` - Ping library mapping +- `compat/CompatST7789.h` - ST7789 compatibility layer -Netgotchi Pro configuration : - -![immagine](https://github.com/user-attachments/assets/8470aba4-9c47-469d-80bb-6da349b01436) +### First Boot +1. On first boot, Netgotchi creates a WiFi hotspot named "AutoConnectAP" +2. Connect to the hotspot and configure your WiFi credentials +3. Once connected, Netgotchi will start guarding your network on the ST7789 display! + +### Key Differences from Original +- **Display**: Uses ST7789 TFT instead of OLED (colors supported!) +- **FTP**: Disabled (stub implementation, no SD card needed) +- **Deauther**: Disabled on ESP32-C6 (ESP8266 feature only) +- **ESP-NOW**: Updated for ESP32 v3.x compatibility ## 🖥️ Headless Mode (for Cyberdecks) @@ -147,18 +225,47 @@ Netgotchi IP and uptime Pro only : move page and setting menu on left button / right button V2 and Pro only : audio alarm on attack -## 😊 Join us on Discord +## 🔧 Troubleshooting (ESP32-C6 Fork) + +### Common Issues +- **ESP-NOW compilation errors**: Ensure all `.ino` files include `globals.h` at the top +- **Missing `minTime()/maxTime()` functions**: Install ESP32Ping library or use only `averageTime()` +- **Display shows nothing**: Check wiring connections and ensure ST7789 library is installed +- **SD_MMC errors**: FTP is disabled in this fork, these errors shouldn't occur +- **WebUI matrix appears empty**: This is normal on ST7789 (no framebuffer for 128×64 matrix view) + +### Legal Notice +**Deauther functions are disabled on ESP32-C6** and may be illegal in many countries. This fork focuses on network monitoring only. + +## 😊 Join Community + +**Original Project Discord**: [Join Now](https://discord.gg/hM4w8eTKrt)! +**Original Reddit Community**: [r/Netgotchi](https://www.reddit.com/r/Netgotchi/) + +> This fork is community-maintained. For original project support, use the official channels above. + +## 🤝 Contributing to This Fork + +We welcome contributions to improve the ESP32-C6 + ST7789 compatibility! Please: +- **Open issues** for bugs or enhancement requests +- **Submit pull requests** with improvements +- **Share optimization ideas** - remember, this was developed with AI assistance +- **Test on different ESP32-C6 boards** and report compatibility -Discord Server: [Join Now](https://discord.gg/hM4w8eTKrt)! +For the original project, please contribute to [MXZZ/Netgotchi](https://github.com/MXZZ/Netgotchi). -## 🤝 Contributing +## 🔄 Fork Information -We welcome contributions! Please submit your pull requests to help make Netgotchi even better. +This is a community fork of the original Netgotchi project, specifically adapted for ESP32-C6 + ST7789 1.47" display compatibility. -Join our [Reddit community](https://www.reddit.com/r/Netgotchi/)! +**Original Project**: [Netgotchi by MXZZ](https://github.com/MXZZ/Netgotchi) +**Fork Author**: [Federicokalik](https://github.com/Federicokalik) +**Fork Focus**: ESP32-C6 + ST7789 display support with Arduino IDE compatibility +**Development**: Fork with ChatGPT-5 Extended Thinking assistance ## 📜 License GNU General Public License v3.0 -Created with ❤️ by MG [MXZZ](https://github.com/MXZZ) | ESP32 Port Created by [itsOwen](https://github.com/itsOwen) +**Original Project** created with ❤️ by MG [MXZZ](https://github.com/MXZZ) | ESP32 Port by [itsOwen](https://github.com/itsOwen) +**ESP32-C6 + ST7789 Fork** by [Federicokalik](https://github.com/Federicokalik) with ChatGPT-5 Extended Thinking assistance diff --git a/images/fork/rgb-working.jpg b/images/fork/rgb-working.jpg new file mode 100644 index 0000000..61167ce Binary files /dev/null and b/images/fork/rgb-working.jpg differ diff --git a/images/fork/screen1.jpg b/images/fork/screen1.jpg new file mode 100644 index 0000000..6b23280 Binary files /dev/null and b/images/fork/screen1.jpg differ diff --git a/images/fork/screen2.jpg b/images/fork/screen2.jpg new file mode 100644 index 0000000..385f47f Binary files /dev/null and b/images/fork/screen2.jpg differ diff --git a/images/fork/screen3.jpg b/images/fork/screen3.jpg new file mode 100644 index 0000000..7a85eb6 Binary files /dev/null and b/images/fork/screen3.jpg differ diff --git a/netgotchi/.claude/settings.local.json b/netgotchi/.claude/settings.local.json new file mode 100644 index 0000000..5a93cbb --- /dev/null +++ b/netgotchi/.claude/settings.local.json @@ -0,0 +1,14 @@ +{ + "permissions": { + "allow": [ + "Read(//c/Users/Calicchia Design/Downloads/Netgotchi-v.1.63/netgotchi-original/Netgotchi---ESP32-C6-LCD-1.47/**)", + "Bash(git checkout:*)", + "Bash(git restore:*)", + "mcp__sequential-thinking__sequentialthinking", + "Bash(grep:*)", + "Bash(git add:*)" + ], + "deny": [], + "ask": [] + } +} \ No newline at end of file diff --git a/netgotchi/ESPping.h b/netgotchi/ESPping.h new file mode 100644 index 0000000..3537bc5 --- /dev/null +++ b/netgotchi/ESPping.h @@ -0,0 +1,10 @@ +#pragma once +#if defined(ARDUINO_ARCH_ESP32) + #include + #define ESPping Ping +#elif defined(ARDUINO_ARCH_ESP8266) + #include + #define ESPping Ping +#else + #error "ESPping compatibility header supports only ESP32/ESP8266." +#endif diff --git a/netgotchi/buttons.ino b/netgotchi/buttons.ino index 44a309a..6ae4581 100644 --- a/netgotchi/buttons.ino +++ b/netgotchi/buttons.ino @@ -1,3 +1,4 @@ +#include "globals.h" //Buttons functions Button2 buttonLeft; diff --git a/netgotchi/compat/CompatST7789.cpp b/netgotchi/compat/CompatST7789.cpp new file mode 100644 index 0000000..9053647 --- /dev/null +++ b/netgotchi/compat/CompatST7789.cpp @@ -0,0 +1,2 @@ +#include "CompatST7789.h" +// All inline. \ No newline at end of file diff --git a/netgotchi/compat/CompatST7789.h b/netgotchi/compat/CompatST7789.h new file mode 100644 index 0000000..a5732a3 --- /dev/null +++ b/netgotchi/compat/CompatST7789.h @@ -0,0 +1,82 @@ +#pragma once +#include +#include +#include +#include + +#ifndef WHITE +#define WHITE ST77XX_WHITE +#endif +#ifndef BLACK +#define BLACK ST77XX_BLACK +#endif + +class CompatST7789 : public Print { +public: + CompatST7789(int8_t cs, int8_t dc, int8_t rst = -1, int16_t w = 240, int16_t h = 240, SPIClass *spi = &SPI) + : _cs(cs), _dc(dc), _rst(rst), _w(w), _h(h), _spi(spi), _tft(cs, dc, rst) {} + + bool begin(uint8_t = 0, uint8_t = 0) { + _spi->begin(); + _tft.init(_w, _h); + _tft.setRotation(_rotation); + _tft.fillScreen(ST77XX_BLACK); + _tft.setTextWrap(false); + return true; + } + + void clearDisplay() { _tft.fillScreen(ST77XX_BLACK); } + void display() {} + void setTextSize(uint8_t s) { _tft.setTextSize(s); } + + void setTextColor(uint16_t c) { + if (c == 0) c = ST77XX_BLACK; + else if (c == 1) c = ST77XX_WHITE; + _tft.setTextColor(c); + } + void setTextColor(uint16_t c, uint16_t bg) { + if (c == 0) c = ST77XX_BLACK; + else if (c == 1) c = ST77XX_WHITE; + if (bg == 0) bg = ST77XX_BLACK; + else if (bg == 1) bg = ST77XX_WHITE; + _tft.setTextColor(c, bg); + } + + void setTextWrap(bool w) { _tft.setTextWrap(w); } + void setCursor(int16_t x, int16_t y) { _tft.setCursor(x, y); } + void setRotation(uint8_t r) { _rotation = r; _tft.setRotation(r); } + int16_t width() const { return _tft.width(); } + int16_t height() const { return _tft.height(); } + + void drawPixel(int16_t x, int16_t y, uint16_t color) { _tft.drawPixel(x, y, color); } + void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { _tft.drawRect(x, y, w, h, color); } + void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) { _tft.fillRect(x, y, w, h, color); } + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) { _tft.drawFastHLine(x, y, w, color); } + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) { _tft.drawFastVLine(x, y, h, color); } + void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) { _tft.drawLine(x0, y0, x1, y1, color); } + void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) { _tft.drawCircle(x0, y0, r, color); } + + void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) { + _tft.drawBitmap(x, y, bitmap, w, h, color); + } + + virtual size_t write(uint8_t c) override { return _tft.write(c); } + + void setBacklightPin(int8_t blPin, bool activeHigh = true) { + _bl = blPin; _blActiveHigh = activeHigh; + if (_bl >= 0) { pinMode(_bl, OUTPUT); digitalWrite(_bl, _blActiveHigh ? HIGH : LOW); } + } + void backlight(bool on) { + if (_bl >= 0) digitalWrite(_bl, (_blActiveHigh ? on : !on) ? HIGH : LOW); + } + + Adafruit_ST7789 &tft() { return _tft; } + +private: + int8_t _cs, _dc, _rst; + int8_t _bl = -1; bool _blActiveHigh = true; + int16_t _w, _h; + uint8_t _rotation = 1; + SPIClass *_spi; + Adafruit_ST7789 _tft; +}; diff --git a/netgotchi/ctrlgotchi.ino b/netgotchi/ctrlgotchi.ino index f4f69d7..7e36ceb 100644 --- a/netgotchi/ctrlgotchi.ino +++ b/netgotchi/ctrlgotchi.ino @@ -1,4 +1,9 @@ -#include +#include "globals.h" + +#include "globals.h" + +#include // richiesto prima di esp_now.h su ESP32 +#include String command[] = {"< ESPNOW RECEIVER >","< ESPNOW SENDER >", "< ON >", "< OFF >" , "< TIMER 1min >", "< TIMER 15min >", "< TIMER 1h >", "< TIMER 8h >"," < ALERT REPEAT 1h>"," < ALERT REPEAT 30m>","< ALERT REPEAT 1m>" }; String ctrlmessage = ""; @@ -102,7 +107,12 @@ void ctrlgotchi_setup() } esp_now_set_self_role(ESP_NOW_ROLE_COMBO); - esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0); + esp_now_peer_info_t peer = {}; +memcpy(peer.peer_addr, broadcastAddress, 6); +peer.ifidx = WIFI_IF_STA; // o WIFI_IF_AP se stai in AP +peer.channel = 1; // metti il tuo canale Wi-Fi se vuoi allinearlo +peer.encrypt = false; +esp_now_add_peer(&peer); esp_now_register_recv_cb(crtlgotchi_OnDataRecv); displayClearDisplay(); diff --git a/netgotchi/deauthergotchi.ino.disbled b/netgotchi/deauthergotchi.ino.disbled new file mode 100644 index 0000000..fb856d6 --- /dev/null +++ b/netgotchi/deauthergotchi.ino.disbled @@ -0,0 +1,173 @@ +#if !defined(ESP8266) +// ESP32/ESP32-C6: modulo deauther non supportato. +// Definiamo stubs vuoti nel caso siano referenziati altrove. +void deauther_setup() {} +void deauther_loop() {} +// Puoi lasciare il resto del file vuoto per ESP32. +#else +extern "C" { + #include "user_interface.h" // solo ESP8266 +} +// ... qui rimane il codice originale per ESP8266 ... +#endif + +String deauth_command[] = {"< SCAN >", "< DEAUTH ALL>", "< STOP >" }; + +int deauth_selectedMode = 0; +int deauth_commandLength = 3; +Button2 deauth_ButtonLeft; +Button2 deauth_ButtonRight; +Button2 deauth_ButtonA; +Button2 deauth_ButtonB; +bool once = false; +bool deauth_showmenu = true; + +void deauthergotchi_setup() +{ + WiFi.mode(WIFI_STA); + WiFi.disconnect(); + delay(100); + displayClearDisplay(); + display.setTextSize(1); + display.setCursor(0, 5); + display.println("DEAUTHERGOTCHI"); + display.println(""); + display.display(); + + + deauth_ButtonLeft.begin(BTN_LEFT); + deauth_ButtonRight.begin(BTN_RIGHT); + deauth_ButtonA.begin(BTN_A); + deauth_ButtonB.begin(BTN_B); + deauth_ButtonLeft.setPressedHandler(deauth_LeftButtonPressed); + deauth_ButtonRight.setPressedHandler(deauth_RightButtonPressed); + deauth_ButtonA.setPressedHandler(deauth_AButtonPressed); + deauth_ButtonB.setPressedHandler(deauth_BButtonPressed); +} + +void deauthergotchi_loop() +{ + + if( deauth_showmenu) + { + display.clearDisplay(); + display.setCursor(0, 5); + display.println("DEAUTHERGOTCHI (v_v)"); + display.println(" "); + display.println(deauth_command[deauth_selectedMode]); + } + if( deauth_selectedMode ==0 && once) + { + scanAndDisplayNetworks(); + once=false; + deauth_showmenu=false; + } + if( deauth_selectedMode ==1 && once) + { + scanNetworksAndDeauth(); + once=false; + deauth_showmenu=false; + } + + display.display(); + + deauth_ButtonLeft.loop(); + deauth_ButtonRight.loop(); + deauth_ButtonA.loop(); + deauth_ButtonB.loop(); +} + + +void deauth_LeftButtonPressed(Button2 &btn) { + deauth_selectedMode--; + if(deauth_selectedMode< 0 )deauth_selectedMode=deauth_commandLength-1; +} + +void deauth_RightButtonPressed(Button2 &btn) { + deauth_selectedMode++; + if(deauth_selectedMode>=deauth_commandLength)deauth_selectedMode=0; +} + +void deauth_AButtonPressed(Button2 &btn) { + //playTone(); + once = true; + deauth_showmenu=false; +} +void deauth_BButtonPressed(Button2 &btn) { + //playTone(); + deauth_showmenu=true; +} + +void scanAndDisplayNetworks() { + int n = WiFi.scanNetworks(); + + display.clearDisplay(); + + if (n == 0) { + display.setCursor(0,0); + display.println("No networks found"); + Serial.println("No networks found"); + display.display(); + return; + } + + int linesPerScreen = SCREEN_HEIGHT / 10; // Calculate how many lines fit on the screen + for (int start = 0; start < n; start += linesPerScreen) { + display.clearDisplay(); + + for (int i = start; i < start + linesPerScreen && i < n; ++i) { + display.setCursor(0, (i - start) * 10); + display.print(i + 1); + display.print(": "); + display.print(WiFi.SSID(i)); + + } + + display.display(); + delay(1000); // Pause to allow reading of the current screen + } + + display.display(); + +} + +void scanNetworksAndDeauth() { + for (int channel = 1; channel <= 13; channel++) { + wifi_set_channel(channel); + int n = WiFi.scanNetworks(); + display.clearDisplay(); + display.setCursor(0,10); + + display.println("Channel :"+String(channel)+" H:"+ String(n) ); + display.display(); + + for (int i = 0; i < n; ++i) { + display.setCursor(0,20); + display.println("attack running:"); + deauthClients(WiFi.BSSID(i)); + delay(100); + display.display(); + } + display.display(); + delay(1000); + display.println("complete!"); + delay(1000); + display.display(); + } +} + +void deauthClients(uint8_t *bssid) { + uint8_t packet[26] = { + 0xC0, 0x00, // Frame Control: Deauthentication + 0x3A, 0x01, // Duration + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], // Destination MAC (BSSID) + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], // Source MAC (BSSID) + bssid[0], bssid[1], bssid[2], bssid[3], bssid[4], bssid[5], // BSSID + 0x00, 0x00 // Sequence Number + }; + + for (int i = 0; i < 500; i++) { // Send multiple packets to ensure disconnection + wifi_send_pkt_freedom(packet, sizeof(packet), false); + delay(10); + } +} \ No newline at end of file diff --git a/netgotchi/espnow.h b/netgotchi/espnow.h new file mode 100644 index 0000000..f6b9ad7 --- /dev/null +++ b/netgotchi/espnow.h @@ -0,0 +1,47 @@ +#ifndef NETGOTCHI_ESPNOW_WRAPPER_H +#define NETGOTCHI_ESPNOW_WRAPPER_H + +#if defined(ARDUINO_ARCH_ESP32) + #include + #include + + #ifndef esp_now_set_self_role + #define esp_now_set_self_role(x) ((void)0) + #endif + #ifndef ESP_NOW_ROLE_COMBO + #define ESP_NOW_ROLE_COMBO 0 + #endif + + typedef void (*espnow_legacy_recv_cb_t)(uint8_t*, uint8_t*, uint8_t); + + static inline espnow_legacy_recv_cb_t& __espnow_legacy_cb_ref() { + static espnow_legacy_recv_cb_t cb = nullptr; + return cb; + } + + static inline void __espnow_new_cb(const esp_now_recv_info * info, const uint8_t *data, int len) { + espnow_legacy_recv_cb_t cb = __espnow_legacy_cb_ref(); + if (!cb) return; + uint8_t mac[6] = {0}; + if (info && info->src_addr) memcpy(mac, info->src_addr, 6); + cb(mac, (uint8_t*)data, (uint8_t)len); + } + + static inline esp_err_t esp_now_register_recv_cb_legacy(espnow_legacy_recv_cb_t cb){ + __espnow_legacy_cb_ref() = cb; + return esp_now_register_recv_cb(__espnow_new_cb); + } + + #ifdef esp_now_register_recv_cb + #undef esp_now_register_recv_cb + #endif + #define esp_now_register_recv_cb(cb) esp_now_register_recv_cb_legacy(cb) + +#elif defined(ARDUINO_ARCH_ESP8266) + #include + #include +#else + #error "ESP-NOW wrapper supports only ESP32/ESP8266." +#endif + +#endif // NETGOTCHI_ESPNOW_WRAPPER_H diff --git a/netgotchi/globals.h b/netgotchi/globals.h new file mode 100644 index 0000000..4d31afb --- /dev/null +++ b/netgotchi/globals.h @@ -0,0 +1,9 @@ +// --- RGB modes (single source of truth) --- +#ifndef RGB_MODES_DEFINED +#define RGB_MODES_DEFINED +enum RGBMode { RGB_MODE_AUTO = 0, RGB_MODE_MANUAL = 1, RGB_MODE_OFF = 2 }; +#endif +#pragma once +#include "pins_local.h" +#include "espnow.h" +#include "ESPping.h" \ No newline at end of file diff --git a/netgotchi/loader.ino b/netgotchi/loader.ino index a46837f..6bceabb 100644 --- a/netgotchi/loader.ino +++ b/netgotchi/loader.ino @@ -1,3 +1,4 @@ +#include "globals.h" //loader vars int selectedMode = 0; @@ -105,7 +106,10 @@ void loadedSetup() ctrlgotchi_setup(); } if(selectedMode == 3){ - deauthergotchi_setup(); + #if defined(ESP8266) +deauthergotchi_setup(); +#endif + } //close the setup loaderSetupSuccess=true; @@ -117,7 +121,10 @@ void loadedLoop() if(selectedMode == 0 ) netgotchi_loop(); if(selectedMode == 1 ) textgotchi_loop(); if(selectedMode == 2 ) ctrlgotchi_loop(); - if(selectedMode == 3 ) deauthergotchi_loop(); + #if defined(ESP8266) +if (selectedMode == 3) deauthergotchi_loop(); +#endif + } void SkipLoader() diff --git a/netgotchi/misc.ino b/netgotchi/misc.ino index 240c78d..72d4c74 100644 --- a/netgotchi/misc.ino +++ b/netgotchi/misc.ino @@ -1,3 +1,4 @@ +#include "globals.h" void countdownToRestart() { //restart in case of connection timeout , retry connection every 5 minutes. diff --git a/netgotchi/netgotchi.ino b/netgotchi/netgotchi.ino index f70e46d..c4c52bd 100644 --- a/netgotchi/netgotchi.ino +++ b/netgotchi/netgotchi.ino @@ -1,83 +1,129 @@ +// ===== Fix pack includes (pulsanti + ESP-NOW + Ping) ===== +#include "globals.h" // include pins_local.h, espnow.h, ESPping.h +extern String status; // usata anche in network.ino + // Netgotchi - lives to protect your network! // Created by MXZZ https://github.com/MXZZ // ESP32 port by itsOwen https://github.com/itsOwen // GNU General Public License v3.0 -// Include necessary libraries based on the board type -#ifdef ESP32 -#include -#include -#include +// ===== Web/WiFi base ===== +#if defined(ESP32) + #include + #include #elif defined(ESP8266) -#include -#include -#include + #include + #include #else -#error "This code is intended to run on ESP32 or ESP8266 platforms only." + #error "This code is intended to run on ESP32 or ESP8266 platforms only." #endif -#include +// Prototipi RGB (definiti in rgb.ino) +void rgbBegin(uint8_t brightness); +void rgbUpdate(); + +#include #include #include -#include #include -#include // Include the WiFiManager library +#include +#include // tzapu #include +// ===== Versione ===== const float VERSION = 1.63; -//Oled Screen Selectors -#define SCREEN_WIDTH 128 +// ===== Disattiva OLED classici (usiamo TFT) ===== +#define SCREEN_WIDTH 128 #define SCREEN_HEIGHT 64 -#define OLED_RESET -1 +#define OLED_RESET -1 -//select to 1 which oled driver you have , default is ssd1306 , ssh1106 for netgotchi pro -#define oled_type_ssd1306 1 -#define oled_type_sh1106 0 +#define oled_type_ssd1306 0 +#define oled_type_sh1106 0 #define oled_type_ssd1305 0 +#define NodeMCU_Oled 0 + +// ===== TFT ST7789 (Waveshare ESP32-C6-LCD-1.47) ===== +#define USE_ST7789 1 +#include "compat/CompatST7789.h" + +// Pinout Waveshare 1.47" (ST7789 172x320) +#define TFT_MOSI 6 +#define TFT_SCLK 7 +#define TFT_CS 14 +#define TFT_DC 15 +#define TFT_RST 21 +#define TFT_BL 22 +#define TFT_W 172 +#define TFT_H 320 + +// --- Logical screen size for ST7789 (landscape 320x172) --- +#if USE_ST7789 + #undef SCREEN_WIDTH + #undef SCREEN_HEIGHT + #define SCREEN_WIDTH 320 // larghezza con rotation(1) + #define SCREEN_HEIGHT 172 // altezza con rotation(1) +#endif +#define HALF_W (SCREEN_WIDTH/2) +#define HALF_H (SCREEN_HEIGHT/2) + +// Istanza display fisico +CompatST7789 display(TFT_CS, TFT_DC, TFT_RST, TFT_W, TFT_H); + +// ===== Backbuffer tipo "video frame" ===== +#define USE_CANVAS_BACKBUFFER 1 +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + // frame 16-bit: 320x172x2 ≈ 110 KB + GFXcanvas16 canvas(SCREEN_WIDTH, SCREEN_HEIGHT); + static inline uint16_t col(int c){ return c ? 0xFFFF : 0x0000; } // WHITE/BLACK +#endif -//For the cheap aliexpress boards with embedded OLED -#define NodeMCU_Oled 1 //set oled type to ssd1306 - -#define BTN_RIGHT 13 -#define BTN_LEFT 12 -#define BTN_A 2 -#define BTN_B 0 -//#define BUZZER_PIN 15 //for netgotchi pro -#define BUZZER_PIN 13 //for netgotchis v2 -#define EXT_PIN_16 16 // D0 on pro - -#if oled_type_ssd1305 -#include -Adafruit_SSD1305 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); -#elif oled_type_sh1106 -#include -Adafruit_SH1106G display = Adafruit_SH1106G(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); -#elif oled_type_ssd1306 -#include -Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET); +// ===== FTP: disabilitato con stub (niente SD_MMC) ===== +#define USE_FTP 0 +#if USE_FTP + #if defined(ESP32) + #include + #elif defined(ESP8266) + #include + #endif + FtpServer ftpSrv; +#else + class FtpServer { + public: + void begin(const char* user = nullptr, const char* pass = nullptr) {} + void init(const char* user = nullptr, const char* pass = nullptr) {} + void handleFTP() {} + bool isConnected() const { return false; } + bool isClientConnected() const { return isConnected(); } // alias compat + String getHoneyPotBreachIPandTime() { return ""; } + }; + FtpServer ftpSrv; #endif -#ifdef ESP32 -WebServer server(80); +// ===== Web server ===== +#if defined(ESP32) + WebServer server(80); #elif defined(ESP8266) -ESP8266WebServer server(80); + ESP8266WebServer server(80); #endif -FtpServer ftpSrv; // Create an instance of the FTP server +// ===== Limiter FPS (usato in screens.ino) ===== +static unsigned long lastFrame = 0; +const uint16_t FRAME_MS = 33; // ~30 FPS +// ===== Starfield / animazione ===== const int NUM_STARS = 100; float stars[NUM_STARS][3]; float ufoX = SCREEN_WIDTH / 2; float ufoY = SCREEN_HEIGHT / 2; float ufoZ = 0; -long timeOffset = 7200; // offset for GMT+2 from https://www.epochconverter.com/timezones - -String status = "Idle"; +// ===== NTP (GMT+2) ===== +long timeOffset = 7200; WiFiUDP ntpUDP; NTPClient timeClient(ntpUDP, "pool.ntp.org", timeOffset); +// ===== Timers / stato UI ===== unsigned long previousMillis = 0; unsigned long previousMillisScan = 0; unsigned long previousMillisPing = 0; @@ -85,11 +131,10 @@ unsigned long previousMillisSoundAlert = 0; unsigned long previouslastEvilTwinCheck = 0; const long interval = 20000; -//delay interval for each screen int screensInterval[] = { 30000, 10000, 10000, 5000, 10000, 5000 }; int i = 0; -int ipnum = 0; // display counter -int iprows = 0; // ip rows +int ipnum = 0; +int iprows = 0; int currentScreen = 0; int maxScreens = 5; @@ -100,11 +145,9 @@ const long intervalPing = 60000 * 5; const long intervalSound = 60000 * 2; const long evilTwinScanInterval = 60000 * 2; - int seconds = 0; unsigned long currentMillis = 0; - int ips[255] = {}; unsigned long lastPingTime = 0; @@ -113,8 +156,12 @@ bool sounds = true; String externalNetworkStatus = ""; String networkStatus = ""; +// stato generico per scansioni / UI +String status = "Idle"; + bool scanOnce = true; String stats = "Not available"; + String netgotchiFace = "(-v_v)"; String netgotchiFace2 = "(v_v-)"; String netgotchiFaceBlink = "( .__.)"; @@ -141,232 +188,313 @@ long serial_info_seconds = 0; int moveX = 0; IPAddress currentIP; -const int flashButtonPin = 0; // GPIO0 is connected to the flash button +const int flashButtonPin = 0; // GPIO0 WiFiManager wifiManager; bool useWifiManager = true; -int wifiManagertimeout = 360; // seconds to run for +int wifiManagertimeout = 360; const char* ssid = ""; const char* password = ""; -bool enableNetworkMode = true; -bool shouldSaveConfig = false; -bool useButtonToResetFlash = true;//false for netgotchi pro -bool hasControlsButtons = false; //true for netgotchi pro -bool skipLoader=true; //false for netgotchi pro -bool debug = true; -bool headless = true; -bool hasDisplay = true; -bool carouselMode = true; -bool scheduledRestart = false; -bool settingMode = false; -bool securityScanActive = true; -bool skipFTPScan = true; -int vulnerabilitiesFound = 0; -int selectedSetting = 0; +bool enableNetworkMode = true; +bool shouldSaveConfig = false; +bool useButtonToResetFlash = true; // false per netgotchi pro +bool hasControlsButtons = false; // true per netgotchi pro +bool skipLoader = true; // false per netgotchi pro +bool debug = true; +bool headless = true; +bool hasDisplay = true; +bool carouselMode = true; +bool scheduledRestart = false; +bool settingMode = false; +bool securityScanActive = true; +bool skipFTPScan = true; +int vulnerabilitiesFound = 0; +int selectedSetting = 0; int settingLength = 6; String settings[] = { "Start AP", "Online Mode", "Airplane Mode", "Start WebInterface", "Restart", "Reset Settings" }; -struct Service { - const char* name; - uint16_t port; -}; - - - - +struct Service { const char* name; uint16_t port; }; Service dangerousServices[] = { - { "Telnet", 23 }, - { "FTP", 21 }, - { "SSH", 22 }, - { "VNC", 5900 }, - { "RDP", 3389 }, - { "SMB", 445 }, - { "HTTP", 80 }, - { "HTTPS", 443 } + { "Telnet", 23 }, { "FTP", 21 }, { "SSH", 22 }, { "VNC", 5900 }, + { "RDP", 3389 }, { "SMB", 445 }, { "HTTP", 80 }, { "HTTPS", 443 } }; - #define MAX_NETWORKS 10 -typedef struct { - String ssid; -} NetworkInfo; - +typedef struct { String ssid; } NetworkInfo; NetworkInfo knownNetworks[MAX_NETWORKS]; -int numKnownNetworks = 0; +int numKnownNetworks = 0; bool evilTwinDetected = false; -bool webInterface = true; +bool webInterface = true; String headlessStatus = ""; - // Broadcast MAC address -uint8_t broadcastAddress[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; - -typedef struct struct_message { - char text[250]; -} struct_message; +uint8_t broadcastAddress[] = { 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF }; +typedef struct struct_message { char text[250]; } struct_message; -static const char PROGMEM pagehtml[] = R"rawliteral( +// ---------------- Web UI page ---------------- +static const char PROGMEM pagehtml[] = R"rawliteral( - Netgotchi - - + Netgotchi + +

Netgotchi


-

Headless display

-

Actual Display

-

Controls

- - - - -
- - -
- - + + + +
+ +
+ + +
+

LED RGB

+
+ +   Mode: + +   Brightness: + +   Color: + +

Hosts

- + )rawliteral"; - -//wrapper functions for display +// ---------------- Wrapper funzioni display (canvas backbuffer) ---------------- void displayPrintln(String line = "") { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.println(line); +#else if (hasDisplay) display.println(line); +#endif } void displaySetCursor(int x, int y) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.setCursor(x, y); +#else if (hasDisplay) display.setCursor(x, y); +#endif } void displayPrint(String line) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.print(line); +#else if (hasDisplay) display.print(line); +#endif } void displayClearDisplay() { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.fillScreen(0x0000); +#else if (hasDisplay) display.clearDisplay(); +#endif } void displaySetSize(int size) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.setTextSize(size); +#else if (hasDisplay) display.setTextSize(size); +#endif } void displaySetTextColor(int color) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.setTextColor(col(color)); +#else if (hasDisplay) display.setTextColor(color); +#endif } -void displayPrintDate(const char* format, int day, int month, int year) { - if (hasDisplay) display.printf(format, day, month, year); +void displayPrintDate(const char* format, int d, int m, int y) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.printf(format, d, m, y); +#else + if (hasDisplay) display.printf(format, d, m, y); +#endif } -void displayDisplay() { - if (hasDisplay) display.display(); +void displayDrawLine(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t color) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.drawLine(x0,y0,x1,y1,col(color)); +#else + if (hasDisplay) display.drawLine(x0,y0,x1,y1,color); +#endif } -void displayDrawLine(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t color) { - if (hasDisplay) display.drawLine(x0, y0, x1, y1, color); +void displayDrawCircle(uint16_t x,uint16_t y,uint16_t r,uint16_t color) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.drawCircle(x,y,r,col(color)); +#else + if (hasDisplay) display.drawCircle(x,y,r,color); +#endif } -void displayDrawCircle(uint16_t x, uint16_t y, uint16_t radius, uint16_t color) { - if (hasDisplay) display.drawCircle(x, y, radius, color); +void displayDrawPixel(uint16_t x,uint16_t y,uint16_t color) { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.drawPixel(x,y,col(color)); +#else + if (hasDisplay) display.drawPixel(x,y,color); +#endif } -void displayDrawPixel(uint16_t x, uint16_t y, uint16_t color) { - if (hasDisplay) display.drawPixel(x, y, color); +void displayFillRect(int16_t x,int16_t y,int16_t w,int16_t h,uint16_t color){ +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (hasDisplay) canvas.fillRect(x,y,w,h,col(color)); +#else + if (hasDisplay) display.fillRect(x,y,w,h,color); +#endif } +// === "Present" della frame: push unico su TFT === +void displayDisplay() { +#if USE_ST7789 && USE_CANVAS_BACKBUFFER + if (!hasDisplay) return; + auto &tft = display.tft(); + tft.startWrite(); + tft.setAddrWindow(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT); + tft.writePixels((uint16_t*)canvas.getBuffer(), (uint32_t)SCREEN_WIDTH * (uint32_t)SCREEN_HEIGHT, true); + tft.endWrite(); +#else + if (hasDisplay) display.display(); +#endif +} +// OLED avevano framebuffer; ST7789 no → per WebUI “matrix” ritorniamo NULL uint8_t* displayGetBuffer() { +#ifdef USE_ST7789 + return NULL; +#else if (hasDisplay) return display.getBuffer(); else return NULL; +#endif } -void SerialPrintLn(String message) { - if (debug) Serial.println(message); -} -void SerialPrintLn(int message) { - if (debug) Serial.println(message); -} - - +// ---------------- Serial helpers ---------------- +void SerialPrintLn(String message){ if (debug) Serial.println(message); } +void SerialPrintLn(int message) { if (debug) Serial.println(message); } + +// ---------------- PROTOTIPI ---------------- +void displayInit(); +void loaderSetup(); +void loader(); +void checkOfflineMode(); +void netgotchiIntro(); +void networkInit(); +void saveCurrentNetworkInfos(); +void buttonsInit(); +void initStars(); +void networkFunctionsLoop(); +void nextScreen(); +void displaySettings(); +void screenAnimations(); +void NetworkStats(); +void displayIPS(); +void displayNetgotchiStats(); +void displayRippleSpace(); +void buttonLoops(); +void controlsButtonLoop(); +void countdownToRestart(); + +// ---------------- Setup / Loop ---------------- void setup() { Serial.begin(115200); - if (NodeMCU_Oled) Wire.begin(14, 12); - displayInit(); + if (NodeMCU_Oled) Wire.begin(14, 12); // disattivo: NodeMCU_Oled=0 + displayInit(); // TFT init loaderSetup(); } @@ -374,20 +502,23 @@ void loop() { loader(); } +// ---------------- Headless info ---------------- void headlessInfo() { if (seconds - serial_info_seconds > 1) { serial_info_seconds = seconds; - headlessStatus = netgotchiCurrentFace + " Honeypot:" + (honeypotTriggered ? "breached" : "OK") + " EvilTwin:" + (evilTwinDetected ? "detected" : "OK") + " Host-Found:" + String(ipnum) + " Vulnerabilities:" + String(vulnerabilitiesFound); + headlessStatus = netgotchiCurrentFace + " Honeypot:" + (honeypotTriggered ? "breached" : "OK") + + " EvilTwin:" + (evilTwinDetected ? "detected" : "OK") + + " Host-Found:" + String(ipnum) + + " Vulnerabilities:" + String(vulnerabilitiesFound); SerialPrintLn(headlessStatus); } } - -void netgotchi_setup() -{ - +// ---------------- Netgotchi lifecycle ---------------- +void netgotchi_setup() { displayInit(); - if(hasControlsButtons)checkOfflineMode(); + rgbBegin(40); // avvia RGB, brightness 0..255 + if (hasControlsButtons) checkOfflineMode(); netgotchiIntro(); if (enableNetworkMode) { @@ -400,21 +531,17 @@ void netgotchi_setup() initStars(); } -void netgotchi_loop() -{ - currentMillis = millis(); +void netgotchi_loop() { + currentMillis = millis(); seconds = currentMillis / 1000; - //main netgotchi network functionalities if (enableNetworkMode) networkFunctionsLoop(); - //display carousel, each screen has a different duration if (!settingMode && carouselMode && (currentMillis - previousMillis >= screensInterval[currentScreen])) { previousMillis = currentMillis; nextScreen(); } - //settings if (settingMode) displaySettings(); if (!settingMode) { @@ -425,12 +552,41 @@ void netgotchi_loop() if (currentScreen == 4) displayRippleSpace(); } - //button loops if (useButtonToResetFlash) buttonLoops(); - if (hasControlsButtons) controlsButtonLoop(); - if (scheduledRestart) countdownToRestart(); + if (hasControlsButtons) controlsButtonLoop(); + if (scheduledRestart) countdownToRestart(); - //headless infos if (headless) headlessInfo(); + rgbUpdate(); // aggiorna animazioni RGB in base allo stato delay(15); } + +// ---------------- Inizializzazione DISPLAY (TFT ST7789) ---------------- +void displayInit() { +#ifdef USE_ST7789 + // SPI esplicita sui pin del Waveshare (nessun MISO) + SPI.begin(TFT_SCLK, /*MISO=*/-1, TFT_MOSI); + + display.begin(); // init ST7789 172x320 + display.setRotation(1); // 1 o 3 = landscape, 0/2 = portrait + display.tft().setSPISpeed(36000000); // 36 MHz; se vedi artefatti scendi a 27 MHz + + // display pulito (sul backbuffer) + displayClearDisplay(); + #if USE_ST7789 && USE_CANVAS_BACKBUFFER + canvas.setTextWrap(false); // evita che i testi “sbordino/ritornino a capo” + #endif + + // retroilluminazione (attiva HIGH su GPIO22) + display.setBacklightPin(TFT_BL, true); + display.backlight(true); + + // riallinea le animazioni al centro del nuovo canvas + ufoX = HALF_W; + ufoY = HALF_H; +#else + // --- Vecchia init OLED --- + // display.begin(SSD1306_SWITCHCAPVCC, 0x3C); + // display.clearDisplay(); +#endif +} \ No newline at end of file diff --git a/netgotchi/network.ino b/netgotchi/network.ino index addcaba..bd732bb 100644 --- a/netgotchi/network.ino +++ b/netgotchi/network.ino @@ -1,13 +1,40 @@ -//Network features +// network.ino — FIX per FTP stub + status + LED REST endpoints + +#include "globals.h" +extern String status; // definita in netgotchi.ino + +#ifndef USE_FTP + #define USE_FTP 0 +#endif + +// Dichiara l’istanza FTP definita in netgotchi.ino (anche quando è lo stub) +class FtpServer; // forward-declare del tipo +extern FtpServer ftpSrv; // variabile globale definita in netgotchi.ino + +// ---- RGB extern/prototipi (definiti in rgb.ino) ---- +extern bool rgb_enabled; +extern uint8_t rgb_brightness; +extern int rgb_mode; +extern uint8_t rgb_manual_r, rgb_manual_g, rgb_manual_b; + +void rgbSetBrightness(uint8_t b); +void rgbEnable(bool en); + +static inline String rgbModeToStr() { + if (rgb_mode == RGB_MODE_MANUAL) return "manual"; + if (rgb_mode == RGB_MODE_OFF) return "off"; + return "auto"; +} + +// Network features void networkInit() { - if (useWifiManager) { displayPrintln("TO Configure WIFI"); displayPrintln("USE: AutoConnectAP"); displayDisplay(); - } else { + } else { displayPrintln("Connecting to WiFi"); displayDisplay(); } @@ -21,18 +48,15 @@ void networkInit() delay(5000); scheduledRestart = true; enableNetworkMode = false; - } - else - { - //connection successfull + } else { + // connection successful displayPrintln("Connection Successful"); displayDisplay(); } - } else { - //use normal wifi credential + // use normal wifi credential WiFi.begin(ssid, password); - while (WiFi.status() != WL_CONNECTED) { + while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); displayPrint("."); @@ -40,96 +64,137 @@ void networkInit() } } - if(webInterface) - { + if (webInterface) { server.on("/", handleRoot); server.on("/matrix", HTTP_GET, [](){ - if(hasDisplay)server.send(200, "application/json", getPixelMatrix()); + if (hasDisplay) server.send(200, "application/json", getPixelMatrix()); else server.send(404); }); server.on("/hosts", HTTP_GET, [](){ - server.send(200, "text/html", getHostsStats()); + server.send(200, "text/html", getHostsStats()); }); server.on("/headless", HTTP_GET, [](){ - server.send(200, "text/html", headlessStatus); + server.send(200, "text/html", headlessStatus); }); server.on("/command/left", HTTP_GET, [](){ - handleCommand("left"); - server.send(200, "text/plain", "Left command received"); + handleCommand("left"); + server.send(200, "text/plain", "Left command received"); }); server.on("/command/right", HTTP_GET, [](){ - handleCommand("right"); - server.send(200, "text/plain", "Right command received"); + handleCommand("right"); + server.send(200, "text/plain", "Right command received"); }); server.on("/command/A", HTTP_GET, [](){ - handleCommand("A"); - server.send(200, "text/plain", "A command received"); + handleCommand("A"); + server.send(200, "text/plain", "A command received"); }); server.on("/command/B", HTTP_GET, [](){ - handleCommand("B"); - server.send(200, "text/plain", "B command received"); + handleCommand("B"); + server.send(200, "text/plain", "B command received"); }); + server.on("/command/ON", HTTP_GET, [](){ - raisePinVoltage(); - server.send(200, "text/plain", "ON command received"); + raisePinVoltage(); + server.send(200, "text/plain", "ON command received"); }); + server.on("/command/OFF", HTTP_GET, [](){ - lowerPinVoltage(); - server.send(200, "text/plain", "OFF command received"); + lowerPinVoltage(); + server.send(200, "text/plain", "OFF command received"); }); + server.on("/command/TIMEPLUS", HTTP_GET, [](){ - timeOffset+=3600; - timeClient.setTimeOffset(timeOffset); - server.send(200, "text/plain", "Hour+ command received"); + timeOffset += 3600; + timeClient.setTimeOffset(timeOffset); + server.send(200, "text/plain", "Hour+ command received"); }); + server.on("/command/TIMEMINUS", HTTP_GET, [](){ - timeOffset-=3600; - timeClient.setTimeOffset(timeOffset); - server.send(200, "text/plain", "Hour- command received"); + timeOffset -= 3600; + timeClient.setTimeOffset(timeOffset); + server.send(200, "text/plain", "Hour- command received"); + }); + + // ---- LED REST endpoints ---- + // Stato corrente (per popolamento UI) + server.on("/led/state", HTTP_GET, [](){ + String json = "{"; + json += "\"enabled\":" + String(rgb_enabled ? "true":"false"); + json += ",\"mode\":\"" + rgbModeToStr() + "\""; + json += ",\"brightness\":" + String(rgb_brightness); + json += ",\"r\":" + String(rgb_manual_r) + ",\"g\":" + String(rgb_manual_g) + ",\"b\":" + String(rgb_manual_b); + json += "}"; + server.send(200, "application/json", json); + }); + + // Set base: enable/disable, mode, brightness + server.on("/led", HTTP_GET, [](){ + if (server.hasArg("enable")) { + rgbEnable(server.arg("enable").toInt() != 0); + } + if (server.hasArg("b")) { + uint8_t b = (uint8_t) constrain(server.arg("b").toInt(), 0, 255); + rgbSetBrightness(b); + } + if (server.hasArg("mode")) { + String m = server.arg("mode"); + if (m == "auto") rgb_mode = RGB_MODE_AUTO; + else if (m == "manual") rgb_mode = RGB_MODE_MANUAL; + else rgb_mode = RGB_MODE_OFF; + } + server.send(200, "text/plain", "OK"); + }); + + // Set colore manuale (quando mode=manual) + server.on("/led/color", HTTP_GET, [](){ + if (server.hasArg("r")) rgb_manual_r = (uint8_t) constrain(server.arg("r").toInt(), 0, 255); + if (server.hasArg("g")) rgb_manual_g = (uint8_t) constrain(server.arg("g").toInt(), 0, 255); + if (server.hasArg("b")) rgb_manual_b = (uint8_t) constrain(server.arg("b").toInt(), 0, 255); + server.send(200, "text/plain", "OK"); }); + // ---- fine LED endpoints ---- server.begin(); } - - currentIP = WiFi.localIP(); SerialPrintLn(currentIP); timeClient.begin(); - ftpSrv.begin("admin", "admin"); // Set FTP username and password - + // FTP opzionale: solo se abilitato + #if USE_FTP + ftpSrv.begin("admin", "admin"); // Set FTP username and password + #endif } void networkFunctionsLoop() { - - //ping scan + // ping scan if (currentMillis - previousMillisScan >= intervalScan) { previousMillisScan = currentMillis; startScan = !startScan; } - //network integrity + // network integrity if (currentMillis - previousMillisPing >= intervalPing) { previousMillisPing = currentMillis; scanOnce = true; } - //sounds alert + // sounds alert if (currentMillis - previousMillisSoundAlert >= intervalSound) { previousMillisSoundAlert = currentMillis; if (sounds && honeypotTriggered) playAlert(); } - // Evil Twin scans + // Evil Twin scans if (currentMillis - previouslastEvilTwinCheck >= evilTwinScanInterval) { previouslastEvilTwinCheck = currentMillis; bool previousEvilTwinStatus = evilTwinDetected; @@ -139,7 +204,7 @@ void networkFunctionsLoop() } } - //Ping Scan + // Ping Scan if (startScan) { if (i < 256) { pingNetwork(i); @@ -151,12 +216,11 @@ void networkFunctionsLoop() } } - //honeypot Checks + // honeypot Checks (solo se FTP attivo) ftpHoneypotScan(); // Handle webInterface requests - if(webInterface) server.handleClient(); - + if (webInterface) server.handleClient(); } void pingNetwork(int i) { @@ -177,14 +241,13 @@ void pingNetwork(int i) { } } } else { - if (ips[i] == -1) ips[i] = 0; - else if (ips[i] == 1) ips[i] = -1; - else if (ips[i] == 2) ips[i] = -1; - else ips[i] = 0; + if (ips[i] == -1) ips[i] = 0; + else if (ips[i] == 1) ips[i] = -1; + else if (ips[i] == 2) ips[i] = -1; + else ips[i] = 0; } } - bool detectEvilTwin() { int numNetworks = WiFi.scanNetworks(); int ssid_count = 0; @@ -192,28 +255,24 @@ bool detectEvilTwin() { for (int i = 0; i < numNetworks; i++) { String ssid = WiFi.SSID(i); - if (ssid == knownNetworks[0].ssid) { - ssid_count++; + ssid_count++; } } - if (ssid_count> 1 ) currentEvilTwinStatus = true; + if (ssid_count > 1) currentEvilTwinStatus = true; if (currentEvilTwinStatus != evilTwinDetected) { - if (currentEvilTwinStatus) { - SerialPrintLn("Evil Twin appeared"); - } else { - SerialPrintLn("Evil Twin disappeared"); - } + if (currentEvilTwinStatus) SerialPrintLn("Evil Twin appeared"); + else SerialPrintLn("Evil Twin disappeared"); } return currentEvilTwinStatus; } - int scanForDangerousServices(IPAddress ip) { WiFiClient client; - for (int i = 0; i < sizeof(dangerousServices) / sizeof(dangerousServices[0]); ++i) { - if (skipFTPScan && dangerousServices[i].name == "FTP") continue; + for (int i = 0; i < (int)(sizeof(dangerousServices) / sizeof(dangerousServices[0])); ++i) { + // evita di testare FTP se skipFTPScan è attivo + if (skipFTPScan && String(dangerousServices[i].name) == "FTP") continue; if (client.connect(ip, dangerousServices[i].port)) { SerialPrintLn("Open port found: "); SerialPrintLn(dangerousServices[i].name); @@ -229,19 +288,23 @@ int scanForDangerousServices(IPAddress ip) { return 0; } - void ftpHoneypotScan() { - ftpSrv.handleFTP(); - #if defined(ESP8266) - if (ftpSrv.returnHoneypotStatus()) { - honeypotTriggered = true; - delay(500); - } + #if USE_FTP + ftpSrv.handleFTP(); + #if defined(ESP8266) + if (ftpSrv.returnHoneypotStatus()) { + honeypotTriggered = true; + delay(500); + } + #else + if (ftpSrv.isClientConnected()) { + honeypotTriggered = true; + delay(500); + } + #endif #else - if (ftpSrv.isClientConnected()) { - honeypotTriggered = true; - delay(500); - } + // FTP disabilitato: nessun honeypot + honeypotTriggered = false; #endif } @@ -250,15 +313,10 @@ void handleRoot() { } void handleCommand(String command) { - if (command == "left") { - handleButtons(BTN_LEFT); - } else if (command == "right") { - handleButtons(BTN_RIGHT); - } else if (command == "A") { - handleButtons(BTN_A); - } else if (command == "B") { - handleButtons(BTN_A); - } + if (command == "left") { handleButtons(BTN_LEFT); } + else if (command == "right") { handleButtons(BTN_RIGHT); } + else if (command == "A") { handleButtons(BTN_A); } + else if (command == "B") { handleButtons(BTN_A); } // intenzionale come nel codice originale } void saveCurrentNetworkInfos() @@ -268,14 +326,11 @@ void saveCurrentNetworkInfos() knownNetworks[0].ssid = WiFi.SSID(); } - String getHostsStats() { - String list = "
"; String ipprefix = String(currentIP[0]) + "." + String(currentIP[1]) + "." + String(currentIP[2]) + "."; for (int j = 0; j < max_ip; j++) { if (ips[j] != 0) { - if (ips[j] == 1) { list += ipprefix + String(j) + " UP" + "
"; } @@ -289,7 +344,3 @@ String getHostsStats() { } return list; } - - - - diff --git a/netgotchi/pins_local.h b/netgotchi/pins_local.h new file mode 100644 index 0000000..3cd9611 --- /dev/null +++ b/netgotchi/pins_local.h @@ -0,0 +1,21 @@ +#define RGB_PIN 8 // pin di controllo RGB della Waveshare +#define RGB_COUNT 1 // numero di LED in catena (parti da 1; se ne vedi più di uno, aumenta) +#pragma once +#ifndef BTN_RIGHT + #define BTN_RIGHT 13 +#endif +#ifndef BTN_LEFT + #define BTN_LEFT 12 +#endif +#ifndef BTN_A + #define BTN_A 2 +#endif +#ifndef BTN_B + #define BTN_B 0 +#endif +#ifndef BUZZER_PIN + #define BUZZER_PIN 13 +#endif +#ifndef EXT_PIN_16 + #define EXT_PIN_16 16 +#endif diff --git a/netgotchi/rgb.ino b/netgotchi/rgb.ino new file mode 100644 index 0000000..b776b94 --- /dev/null +++ b/netgotchi/rgb.ino @@ -0,0 +1,106 @@ +#include +#include // per WiFi.status() + +// --- pin/count (Waveshare ESP32-C6-LCD-1.47) --- +#ifndef RGB_PIN + #define RGB_PIN 8 +#endif +#ifndef RGB_COUNT + #define RGB_COUNT 1 +#endif + +// --- variabili globali controllabili da WebUI --- +bool rgb_enabled = true; +uint8_t rgb_brightness = 60; // 0..255 +int rgb_mode = RGB_MODE_AUTO; +uint8_t rgb_manual_r = 255, rgb_manual_g = 255, rgb_manual_b = 255; + +Adafruit_NeoPixel rgb(RGB_COUNT, RGB_PIN, NEO_GRB + NEO_KHZ800); + +// extern da altri file (usati per lo stato) +extern bool honeypotTriggered; +extern bool evilTwinDetected; +extern int vulnerabilitiesFound; +extern bool startScan; +extern bool useWifiManager; + +// ------------ helpers -------------- +static inline void rgbAll(uint8_t r, uint8_t g, uint8_t b) { + for (int i = 0; i < RGB_COUNT; i++) + rgb.setPixelColor(i, rgb.Color(r, g, b)); + rgb.show(); +} +static inline void rgbOff() { rgb.clear(); rgb.show(); } + +// onda 0..1 +static inline float wave01(uint16_t period_ms) { + uint16_t t = millis() % period_ms; + return (t < period_ms/2) ? (t/(period_ms/2.0f)) : ((period_ms - t)/(period_ms/2.0f)); +} + +// ------------ API invocabili da altri file -------------- +void rgbBegin(uint8_t brightness) { + rgb.begin(); + rgb.setBrightness(brightness); + rgb_brightness = brightness; + if (rgb_enabled) rgbAll(0, 32, 0); else rgbOff(); +} + +void rgbSetBrightness(uint8_t b) { + rgb_brightness = b; + rgb.setBrightness(b); + rgb.show(); +} + +void rgbEnable(bool en) { + rgb_enabled = en; + if (!en) rgbOff(); +} + +// loop non bloccante: sceglie colore/animazione in base allo stato +void rgbUpdate() { + if (!rgb_enabled || rgb_mode == RGB_MODE_OFF) { rgbOff(); return; } + + if (rgb_mode == RGB_MODE_MANUAL) { + rgbAll(rgb_manual_r, rgb_manual_g, rgb_manual_b); + return; + } + + // ---- modalità AUTO: priorità dei problemi > config > ok ---- + // 1) Problemi / intrusioni + if (honeypotTriggered) { + // flash rosso/blu veloce + bool phase = ((millis()/120) % 2) == 0; + if (phase) rgbAll(255, 0, 0); else rgbAll(0, 0, 255); + return; + } + if (evilTwinDetected) { + // respiro blu + uint8_t v = (uint8_t)(wave01(900) * 255); + rgbAll(0, 0, v); + return; + } + if (vulnerabilitiesFound > 0) { + // respiro rosso + uint8_t v = (uint8_t)(wave01(1000) * 255); + rgbAll(v, 0, 0); + return; + } + + // 2) Connessione/config + if (useWifiManager || WiFi.status() != WL_CONNECTED || startScan) { + // respiro arancio/giallo + float p = wave01(1100); + uint8_t r = 255; + uint8_t g = (uint8_t)(160 + (95 * p)); // 160..255 (arancio→giallo) + rgbAll(r, g, 0); + return; + } + + // 3) Tutto OK → bianco/verde (respiro morbido) + float p = wave01(1400); + uint8_t g = (uint8_t)(80 + 175 * p); // 80..255 + uint8_t r = (uint8_t)(40 + 120 * p/2.0); // leggero bianco + uint8_t b = (uint8_t)(40 + 120 * p/2.0); + rgbAll(r, g, b); +} diff --git a/netgotchi/screens.ino b/netgotchi/screens.ino index 22646cc..b973e60 100644 --- a/netgotchi/screens.ino +++ b/netgotchi/screens.ino @@ -1,43 +1,107 @@ -//Screens functions - - - -void displayInit() -{ - //to skip if the board has not display - if(hasDisplay) - { - //display initializer - if(oled_type_ssd1306){ - // spefify your pins if needed - // Wire.begin(D5, D6); - if (!display.begin(2, 0x3C)) { - // add "SSD1306_SWITCHCAPVCC, 0x3C" in the begin() if screen doesn't work. +// Screens functions — margini e testi ottimizzati per ST7789 320x172 + +// --- Se stai usando ST7789, la displayInit() è in netgotchi.ino --- +#ifdef USE_ST7789 +// nothing here +#else +void displayInit() { + if (hasDisplay) { + if (oled_type_ssd1306) { + if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { SerialPrintLn("SSD1306 allocation failed"); for (;;); } - } - else - { - if (!display.begin()) { + } else { + if (!display.begin()) { SerialPrintLn("Display allocation failed"); for (;;); } } } } +#endif + +// ---------- Layout helpers ---------- +static const int FONT_W = 6; // font classico Adafruit_GFX +static const int FONT_H = 8; +static const int UI_MARGIN_X = 12; // margine sinistro/destro +static const int UI_MARGIN_Y = 8; // margine alto/basso + +static inline int textW(const String &s, int size) { return (int)s.length() * FONT_W * size; } +static inline int textH(int size) { return FONT_H * size; } + +// setCursor con margine (comodo per elementi a sinistra) +static inline void setCursorM(int x, int y) { displaySetCursor(x + UI_MARGIN_X, y + UI_MARGIN_Y); } + +// setCursor allineato a destra (x = bordo destro - margine - larghezza testo) +static inline void setCursorRight(const String& s, int y, int size) { + int x = SCREEN_WIDTH - UI_MARGIN_X - textW(s, size); + displaySetCursor(x, y + UI_MARGIN_Y); + displaySetSize(size); +} + +// setCursor in basso a sinistra +static inline void setCursorBL(int size) { + int y = SCREEN_HEIGHT - UI_MARGIN_Y - textH(size); + displaySetCursor(UI_MARGIN_X, y); + displaySetSize(size); +} + +// setCursor in basso a destra con una stringa di riferimento +static inline void setCursorBR(const String& s, int size) { + int y = SCREEN_HEIGHT - UI_MARGIN_Y - textH(size); + int x = SCREEN_WIDTH - UI_MARGIN_X - textW(s, size); + displaySetCursor(x, y); + displaySetSize(size); +} + +/* ====== Faccine centrate (senza confliggere con faces.ino) ====== */ + +// restituisce la faccina in base allo stato (riusa le stringhe globali) +static inline String faceByState_(int s) { + switch (s % 6) { + case 0: return netgotchiFace; // "(-v_v)" + case 1: return netgotchiFace2; // "(v_v-)" + case 2: return netgotchiFaceBlink; // "( .__.)" + case 3: return netgotchiFaceHappy; // "(^=^)" + case 4: return netgotchiFaceSurprised; // "(o__o)" + default: return netgotchiFaceSleep; // "(-__- )" + } +} + +// stampa la faccina centrata orizzontalmente (font size 2) con jitter clampato ai margini +void drawnetgotchiFaceCentered(int state) { + const int size = 2; + String face = faceByState_(state); + + int w = textW(face, size); + int h = textH(size); + + // centro + jitter (moveX) limitato ai margini + int x = (SCREEN_WIDTH - w) / 2 + moveX; + if (x < UI_MARGIN_X) x = UI_MARGIN_X; + if (x > SCREEN_WIDTH - UI_MARGIN_X - w) x = SCREEN_WIDTH - UI_MARGIN_X - w; + + // verticale: un filo sopra il centro + int y = (SCREEN_HEIGHT - h) / 2 - 6; + + displaySetTextColor(1); + displaySetSize(size); + displaySetCursor(x, y); + displayPrint(face); +} +/* =============================================================== */ +// ---------- Schermate ---------- void drawSpace() { displayClearDisplay(); updateAndDrawStars(); drawUFO(); - if(enableNetworkMode) - { + + if (enableNetworkMode) { displayTimeAndDate(); displayStats(); - } - else - { + } else { displayOfflineMode(); } displayDisplay(); @@ -49,13 +113,10 @@ void displayRippleSpace() { drawRipple(); netgotchi_face(); - if(enableNetworkMode) - { + if (enableNetworkMode) { displayTimeAndDate(); displayStats(); - } - else - { + } else { displayOfflineMode(); } displayDisplay(); @@ -64,32 +125,41 @@ void displayRippleSpace() { void NetworkStats() { displayClearDisplay(); - displaySetCursor(0, 8); - if (WiFi.status() == WL_CONNECTED) networkStatus = "connected"; - else networkStatus = "disconnected"; - displayPrint("Network: " + networkStatus); - displaySetCursor(0, 16); + // Titolo stato rete (sinistra) + displaySetTextColor(1); + displaySetSize(2); + setCursorM(0, 0); + networkStatus = (WiFi.status() == WL_CONNECTED) ? "connected" : "disconnected"; + displayPrint("Net: " + networkStatus); + + // Ping solo una volta per ciclo + displaySetSize(1); + setCursorM(0, textH(2) + 2); if (scanOnce) { - IPAddress ip(1, 1, 1, 1); // ping cloudflare + IPAddress ip(1, 1, 1, 1); // Cloudflare SerialPrintLn("pinging cloudflare"); - if (Ping.ping(ip, 2)) { externalNetworkStatus = "Reachable"; - displayPrintln(); scanOnce = false; - stats = "\n min: " + String(Ping.minTime()) + "ms \n avg: " + String(Ping.averageTime()) + "ms \n max: " + String(Ping.maxTime()) + "ms"; - delay(500); + stats = "avg: " + String(Ping.averageTime()) + "ms"; SerialPrintLn("ping sent"); SerialPrintLn(stats); - } else externalNetworkStatus = "Unreachable"; + } else { + externalNetworkStatus = "Unreachable"; + stats = "avg: n/a"; + } } - displayPrintln("Network Speed: " + stats); - displayPrintln("Internet: " + externalNetworkStatus); - displayDisplay(); -} + displayPrint("Speed: " + stats); + // Internet status (riga sotto) + setCursorM(0, textH(2) + textH(1) + 6); + displayPrint("Internet: " + externalNetworkStatus); + // HUD standard + displayStats(); + displayDisplay(); +} void initStars() { for (int i = 0; i < NUM_STARS; i++) { @@ -123,16 +193,13 @@ void drawUFO() { ufoY = SCREEN_HEIGHT / 2 + cos(millis() / 1500.0) * 10; } - int frame = 0; -int numCircles = 10; -int maxRadius = 70; -void drawRipple() -{ - int radius = (frame * 10) % maxRadius; +int maxRadius = 120; +void drawRipple() { + int radius = (frame * 10) % maxRadius; displayDrawCircle(SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, radius, 1); frame++; - delay(100); + delay(90); } void displayTimeAndDate() { @@ -144,217 +211,220 @@ void displayTimeAndDate() { int currentMonth = ptm->tm_mon + 1; int currentYear = ptm->tm_year + 1900; - displaySetSize(1); + // Ora in grande displaySetTextColor(1); - displaySetCursor(5, 0); + displaySetSize(2); + setCursorM(0, 0); displayPrint(formattedTime); - displaySetCursor(0, 8); + + // Data subito sotto + displaySetSize(1); + setCursorM(0, textH(2)); displayPrintDate("%02d/%02d/%d", currentDay, currentMonth, currentYear); - + + // Honeypot in alto a destra + displaySetSize(1); + String hp = "Honeypot"; + setCursorRight(hp, 0, 1); + displayPrint(hp); + setCursorRight(hp, textH(1), 1); + displayPrint(honeypotTriggered ? "BREACHED" : "OK"); } -void displayStats() -{ - displaySetCursor(0, 55); - displayPrint("Hosts:" + String(ipnum) + " VU:" + String(vulnerabilitiesFound)); - displaySetCursor(75, 0); - displayPrint("Honeypot"); - if (honeypotTriggered) { - if (((seconds % 2) == 0)) { - displaySetCursor(80, 8); - displayPrint("Breached"); - displaySetCursor(40, 16); - - #if defined(ESP8266) - displayPrint(ftpSrv.getHoneyPotBreachIPandTime()); - #endif - } - } else { - displaySetCursor(80, 8); - displayPrint("OK"); - } +void displayStats() { + // Basso sinistra: Hosts/VU + displaySetTextColor(1); + setCursorBL(1); + displayPrint("Hosts:" + String(ipnum) + " VU:" + String(vulnerabilitiesFound)); - displaySetCursor(90, 55); - if (startScan) - displayPrint("Scan"); - else displayPrint("Idle"); + // Basso destra: stato scan/idle + String mode = startScan ? "Scan" : "Idle"; + setCursorBR(mode, 1); + displayPrint(mode); } void displayIPS() { displayClearDisplay(); - displaySetCursor(0, 0); - displayPrintln("Found Hosts:"); + displaySetTextColor(1); - if(ipnum>0) { + // Titolo + displaySetSize(2); + setCursorM(0, 0); + displayPrint("Found Hosts"); + + // Lista (font 1, righe da 12px) + displaySetSize(1); + int lineY = textH(2) + 6; + + if (ipnum > 0) { String ipprefix = String(currentIP[0]) + "." + String(currentIP[1]) + "." + String(currentIP[2]) + "."; + int shown = 0; for (int j = 0; j < max_ip; j++) { if (ips[j] == 1 || ips[j] == -1 || ips[j] == 2) { - if (iprows >= 4) { - displayClearDisplay(); - displaySetCursor(5, 0); - displayPrintln("Hosts:" + String(ipnum)); - iprows = 0; - } - displaySetCursor(0, 20 + (iprows)*10); - if (ips[j] == 1) { - String al = ipprefix + String(j) + " UP"; - displayPrintln(al); - iprows++; + if (lineY > SCREEN_HEIGHT - UI_MARGIN_Y - textH(1)) { + // pagina successiva semplice: ferma qui e lascia HUD + break; } - if (ips[j] == 2) { - String al = ipprefix + String(j) + " WRNG!"; - displayPrintln(al); - iprows++; - } - if (ips[j] == -1) { - String dc = ipprefix + String(j) + " DOWN"; - displayPrintln(dc); - iprows++; - } - - delay(500); - if (iprows == 4) delay(1000); - displayDisplay(); + setCursorM(0, lineY); + if (ips[j] == 1) displayPrint(ipprefix + String(j) + " UP"); + else if (ips[j] == 2) displayPrint(ipprefix + String(j) + " WARN!"); + else if (ips[j] == -1) displayPrint(ipprefix + String(j) + " DOWN"); + lineY += 12; + shown++; } } + } else { + // Nessun host: passa alla prossima schermata + nextScreen(); } - else nextScreen(); + + // HUD + displayStats(); + displayDisplay(); } -void displayNetgotchi() -{ +void displayNetgotchi() { displayClearDisplay(); updateAndDrawStars(); - if(enableNetworkMode) - { + if (enableNetworkMode) { displayTimeAndDate(); displayStats(); + } else { + displayOfflineMode(); } - else displayOfflineMode(); netgotchi_face(); displayDisplay(); - } void netgotchi_face() { - - displaySetSize(2); - drawnetgotchiFace(animState); + // faccina centrata + drawnetgotchiFaceCentered(animState); + // animazione tempo + jitter if (seconds - old_seconds > 1) { moveX = moveX + random(-5, 5); - if (moveX > 20) moveX = 5; + if (moveX > 20) moveX = 5; if (moveX < -20) moveX = -5; old_seconds = seconds; - animState++; - if (animState > 5) animState = 0; + animState = (animState + 1) % 6; } + + // ripristina size predefinito per l'HUD displaySetSize(1); } - -void displayOfflineMode() -{ - displaySetCursor(0, 55); +void displayOfflineMode() { + setCursorBL(1); displayPrint("Netgotchi is Offline"); } -void netgotchiIntro() -{ +void netgotchiIntro() { displayClearDisplay(); + displaySetTextColor(1); + + // Titolo grande + displaySetSize(2); + setCursorM(0, 0); + displayPrint("Netgotchi v." + String(VERSION) + "-C6"); + + // Sottotitolo displaySetSize(1); - displaySetTextColor(1); //white color - displaySetCursor(0, 0); - displayPrintln("Netgotchi v." + String(VERSION)); - displayPrintln("created by MXZZ "); - delay(500); + setCursorM(0, textH(2) + 6); + displayPrint("Forked by Federicokalik"); + displayDisplay(); + delay(700); } -void displaySettings() -{ +void displaySettings() { displayClearDisplay(); - displaySetCursor(0, 0); - displayPrintln("Settings v." + String(VERSION)); - displaySetCursor(0, 10); - - for(int i=0; i< settingLength ;i++) - { - if(selectedSetting == i) - displayPrintln(">"+settings[i]); - else - displayPrintln(" "+settings[i]); + displaySetTextColor(1); + + // Titolo + displaySetSize(2); + setCursorM(0, 0); + displayPrint("Settings v." + String(VERSION)); + + // Voci (font 1) + displaySetSize(1); + int y = textH(2) + 6; + for (int i = 0; i < settingLength; i++) { + setCursorM(0, y); + if (selectedSetting == i) displayPrint(">" + settings[i]); + else displayPrint(" " + settings[i]); + y += 12; } displayDisplay(); } -void displayNetgotchiStats(){ +void displayNetgotchiStats() { displayClearDisplay(); - displaySetCursor(0, 0); - displayPrintln("Netgotchi v." + String(VERSION)); - displaySetCursor(0, 10); + displaySetTextColor(1); + + // Titolo + displaySetSize(2); + setCursorM(0, 0); + displayPrint("Netgotchi v." + String(VERSION) + "-C6"); - displayPrintln("IP: " + currentIP.toString() ); - displayPrintln("Uptime:" + String(seconds)+"sec"); - if( WiFi.status() == WL_CONNECTED)displayPrintln("SSID:" + WiFi.SSID()); + // Info (font 1, spaziatura 12) + displaySetSize(1); + int y = textH(2) + 6; + setCursorM(0, y); displayPrint("IP: " + currentIP.toString()); y += 12; + setCursorM(0, y); displayPrint("Uptime: " + String(seconds) + "s"); y += 12; + if (WiFi.status() == WL_CONNECTED) { + setCursorM(0, y); displayPrint("SSID: " + WiFi.SSID()); y += 12; + } - + // HUD + displayStats(); displayDisplay(); } -void screenAnimations() -{ - //animations loop on the same carousel page - +void screenAnimations() { if (animation == 0) displayNetgotchi(); if (animation == 1) drawSpace(); if (animation > max_anim) animation = 0; } - int getPixelAt(int x, int y) { - // Check if coordinates are within bounds - if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) { - return -1; // Out of bounds - } - - // Calculate the index of the byte in the buffer - int byteIndex = (y / 8) * SCREEN_WIDTH + x; // Find which byte - int bitIndex = y % 8; // Find which bit within the byte - - // Get the byte value from the buffer - uint8_t* buffer = displayGetBuffer(); - uint8_t byteValue = buffer[byteIndex]; - - // Check if the pixel is set (1 for white, 0 for black) - bool isWhite = (byteValue & (1 << bitIndex)) != 0; - return isWhite ? 1 : 0; + if (x < 0 || x >= SCREEN_WIDTH || y < 0 || y >= SCREEN_HEIGHT) return -1; +#ifdef USE_ST7789 + // ST7789 non ha framebuffer → WebUI "matrix" ritorna 0 (nero) + return 0; +#else + int byteIndex = (y / 8) * SCREEN_WIDTH + x; + int bitIndex = y % 8; + uint8_t* buffer = displayGetBuffer(); + if (!buffer) return 0; + uint8_t byteValue = buffer[byteIndex]; + bool isWhite = (byteValue & (1 << bitIndex)) != 0; + return isWhite ? 1 : 0; +#endif } String getPixelMatrix() { - String matrix = "["; - for (int y = 0; y < SCREEN_HEIGHT; y++) { - if (y > 0) matrix += ","; - matrix += "["; - for (int x = 0; x < SCREEN_WIDTH; x++) { - if (x > 0) matrix += ","; - matrix += getPixelAt(x, y); - } - matrix += "]"; + String matrix = "["; + for (int y = 0; y < SCREEN_HEIGHT; y++) { + if (y > 0) matrix += ","; + matrix += "["; + for (int x = 0; x < SCREEN_WIDTH; x++) { + if (x > 0) matrix += ","; + matrix += getPixelAt(x, y); } matrix += "]"; - return matrix; + } + matrix += "]"; + return matrix; } -void nextScreen(){ +void nextScreen() { currentScreen++; if (currentScreen > maxScreens) { currentScreen = 0; - //change animation animation++; - if(animation>max_anim)animation=0; + if (animation > max_anim) animation = 0; } } diff --git a/netgotchi/textgotchi.ino b/netgotchi/textgotchi.ino index 33a5e08..f181bdb 100644 --- a/netgotchi/textgotchi.ino +++ b/netgotchi/textgotchi.ino @@ -1,4 +1,4 @@ -#include +#include "globals.h" const char keyboard_chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "; int selected_keyboard_index = 0; @@ -47,7 +47,13 @@ void textgotchi_setup() } esp_now_set_self_role(ESP_NOW_ROLE_COMBO); - esp_now_add_peer(broadcastAddress, ESP_NOW_ROLE_COMBO, 1, NULL, 0); +esp_now_peer_info_t peer = {}; +memcpy(peer.peer_addr, broadcastAddress, 6); +peer.ifidx = WIFI_IF_STA; // o WIFI_IF_AP se stai in AP +peer.channel = 1; // metti il tuo canale Wi-Fi se vuoi allinearlo +peer.encrypt = false; +esp_now_add_peer(&peer); + esp_now_register_recv_cb(OnDataRecv); displayClearDisplay();