51 Commits
v1.0 ... v1.1

Author SHA1 Message Date
a5a78d442b Merge branch 'main' of https://git.kopic.hr/tomislav/SmartCubeV1 2025-09-15 22:26:57 +02:00
d2bf95d944 Allow skipping WiFi setup 2025-09-15 22:26:22 +02:00
a90d6f2188 Update WiFi manager and demo screen behavior 2025-09-15 22:26:08 +02:00
6b116edbe1 Update Readme.md 2025-09-15 12:54:46 +00:00
ffc1d774a9 Update Readme.md 2025-09-15 12:36:08 +00:00
4364b598b8 Update Readme.md 2025-09-15 12:23:08 +00:00
4f670beed8 Fix typos in Readme.md 2025-09-15 12:10:26 +00:00
6e6355ae43 Update Readme.md 2025-09-15 10:45:41 +00:00
a18970713d Update Readme.md 2025-09-15 10:34:16 +00:00
ae2c90f962 Update Readme 2025-09-13 21:26:11 +02:00
5b2e06d60c Update readme 2025-09-13 21:20:13 +02:00
e065c5e4b1 Upload files to "hardware/case" 2025-08-01 15:26:29 +00:00
fb57c3b36a Delete hardware/case/SmartCube_Back_Speaker_Power_Switch.stl 2025-08-01 15:26:18 +00:00
00ea56538e Upload files to "hardware/case" 2025-08-01 13:36:27 +00:00
2bc6c6fde6 Delete SmartCube_Back_Speaker_Power_Switch.stl 2025-08-01 13:36:12 +00:00
b48b501536 Upload files to "/" 2025-08-01 13:35:47 +00:00
34cd4ecf19 Update Readme.md 2025-08-01 07:59:27 +00:00
5d0a5af8e2 Update Readme.md 2025-08-01 07:54:57 +00:00
4202cfda2d Update Readme.md 2025-08-01 07:50:44 +00:00
83a8b6f028 Update Readme.md 2025-08-01 07:45:55 +00:00
60dbd3852c Update Readme.md 2025-08-01 07:42:49 +00:00
2b23f8e9c7 Upload files to "hardware/case" 2025-08-01 07:41:02 +00:00
21d05927d1 Update Readme.md 2025-08-01 07:39:55 +00:00
11fcf377aa Update Readme.md 2025-08-01 07:21:49 +00:00
121134d5ba Update Readme.md 2025-08-01 07:20:39 +00:00
7de1b86307 Update Readme.md 2025-08-01 07:15:35 +00:00
1cb51f502d Update Readme.md 2025-07-30 08:33:28 +00:00
516366f07d Update Readme.md 2025-07-30 08:23:32 +00:00
0d98b7e407 Update Readme.md 2025-07-30 08:13:57 +00:00
ae65034e69 Update Readme.md 2025-07-30 07:56:33 +00:00
b55ff78b40 Update Readme.md 2025-07-30 07:53:22 +00:00
e61ad3eea0 Update Readme.md 2025-07-30 07:49:53 +00:00
a4d9b673f5 Update Readme.md 2025-07-30 07:47:21 +00:00
eace77376b Update Readme.md 2025-07-30 07:43:34 +00:00
81077a46f2 Update Readme.md 2025-07-30 07:39:49 +00:00
52a41ce3c2 Update Readme.md 2025-07-30 07:33:44 +00:00
7e99fcb52e Update Readme.md 2025-07-30 07:30:56 +00:00
de99a11163 Upload files to "hardware/pictures" 2025-07-30 07:24:58 +00:00
63f26b1acc Upload files to "hardware/pictures" 2025-07-30 07:20:50 +00:00
2d31de8fa8 Upload files to "hardware/pictures" 2025-07-30 07:19:52 +00:00
f491e6a24b Upload files to "hardware/pictures" 2025-07-30 07:19:26 +00:00
16b5c34491 Update Readme.md 2025-07-30 07:06:20 +00:00
8935af57d2 Update Readme.md 2025-07-30 07:03:58 +00:00
80b9293f0e Update Readme.md 2025-07-30 07:02:42 +00:00
6e503dd3f9 Update 2024-12-07 08:10:42 +01:00
80def4cc43 Add screws to the bill of materials 2024-12-07 08:09:00 +01:00
809c73b15b Fix 2024-12-07 07:58:44 +01:00
010d253afa fix 2024-12-07 07:55:20 +01:00
6124a73846 add picture 2024-12-07 07:53:40 +01:00
9a339ee380 Edit Readme 2024-12-07 07:48:32 +01:00
1d6ad2a481 Add readme 2024-12-07 07:33:44 +01:00
27 changed files with 325 additions and 18 deletions

6
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"files.associations": {
"functional": "cpp",
"cmath": "cpp"
}
}

190
Readme.md Normal file
View File

@@ -0,0 +1,190 @@
# SmartCube
**SmartCube** is a tiny and customizable desk toy using the ESP8266 D1 Mini.
Built entirely from cheap, easy-to-find parts, it can connect to Wi-Fi and can be programmed to do just about anything:
show notifications, display the weather, monitor stuff, show a clock, serve a web site, mine crypto, be a virtual pet or whatever else your caffeine-fueled brain can imagine.
![SmartCube](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/cubez.jpg)
---
## Info
- **This is a hobby project I work on and develop for when I have literally nothing else to do, do not expect regular updates. You are free to clone this and do whatever you like with it**
- **Code**: I have a few projects developed for the Cube. You can see the list [here on my Gitea](https://git.kopic.hr/tomislav?tab=repositories&q=cube&sort=recentupdate)
- **V2**: There is also a more [powerful version](https://git.kopic.hr/tomislav/SmartCubeV2), it's pretty much the same but with extra features and is using ESP32, I only made one of them and I don't like it yet, it needs work.
- **Case**: 3D-printable design included in `/hardware` directory
- **Schematics**: and assembly instructions are also in the `/hardware` directory
---
## Demo Code Explanation
This repository contains a basic "Hello, World!" project for the SmartCube.
### Getting Started:
1. Download and install **[VSCode](https://code.visualstudio.com/)** or **[VSCodium](https://vscodium.com/)**.
2. Install the **[PlatformIO IDE extension](https://platformio.org/platformio-ide)**.
3. Clone this repository and open the project folder in VSCode/VSCodium.
4. PlatformIO will automatically handle environment setup and dependencies when you open the project.
### Project Structure:
All source code is located in the `src/` directory.
You should start by opening **`src/main.cpp`**, which contains the entry point and initialization logic.
### What the Code Does:
This demo handles basic system functionality, including:
* System initialization
* Button input handling
* OLED display output configuration
* WiFi management
### Key Features
1. **WiFi Management**:
- The [cubeWifiManager](https://git.kopic.hr/tomislav/SmartCubeV1/src/branch/main/src/SmartCube/cubeWifiManager.h) class manages WiFi connectivity seamlessly.
- If no known WiFi network is available, it starts a configuration portal and creates an access point (AP), allowing users to connect the SmartCube to a network from another WiFi-enabled device.
- The OLED display shows the access point details, such as the AP name and IP address, making the setup process very easy.
2. **Button Handling**:
- Buttons are mapped to specific GPIO pins: `PIN_BTN_L` (Left), `PIN_BTN_M` (Middle), and `PIN_BTN_R` (Right).
- The [cubeButtonHandler](https://git.kopic.hr/tomislav/SmartCubeV1/src/branch/main/src/SmartCube/cubeButtons.h) function, executed in the [loop()](https://git.kopic.hr/tomislav/SmartCubeV1/src/commit/1cb51f502d92a91c6a83ce6364b434db31bfd864/src/main.cpp#L47), monitors and interprets button presses, differentiating between short and long presses.
#### Default Button Actions
- **Right Button**:
- *Short Press*: Turns the OLED display **on** (if previously off).
- *Long Press*: Turns the OLED display **off**, helping conserve power.
- **Left + Middle Buttons (Simultaneous Long Press)**:
- Triggers an ESP8266 reboot, effectively restarting the device.
This is meant to provide a minimal starting point for further development with the SmartCube.
---
## Bill of Materials
| **Component** | **Quantity** | **Description** | **Notes** |
|---------------------------|--------------|-------------------------------------------|---------------------------------------------|
| ESP8266 D1 Mini | 1 | Microcontroller module | |
| SSD1306 OLED Display | 1 | 128x64 resolution, I2C interface | |
| 14250 Rechargeable Battery| 1 | Lithium-ion battery | Make sure you get the rechargeable type, most 14250 are not |
| TP4056 Module | 1 | Charging and protection circuit | Does not need to have a USB connector |
| 6x6 Push Buttons | 3 or 4 | Tactile push buttons | |
| 20mm Piezo Buzzer | 1 | Caseless buzzer for audio | |
| Resistors (10kΩ) | 3 or 4 | Pull-down resistors for buttons | |
| Resistors (220kΩ and 56kΩ)| 1 | Voltage divider | For monitoring the battery charge level |
| Wires | Several | Thin wires for connections | I used wires from inside an old ethernet cable |
| Enclosure | 1 | 3D-printed case | 3D printable STL files are in `hardware/case/` |
| 2x6mm screw | 8 | Small screws for assembling the case | Does not have to be exactly 6mm long |
| 2x2mm screw | 4 | Small screws for the front | Mostly for cosmetic purposes |
![layout](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/layout.jpg)
---
## Assembly Instructions
---
1. **Body**
Push the ESP8266 microcontroller in the ledge on the bottom [the cube body](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/case/SmartCube_Body_3_button.stl), it should 'click in' with the USB-C port facing the hole.
Body with 3 or 4 button slots is available in the `hardware/case/`
![Step3](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build3.jpg)
![Step1](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build1.jpg)
![Step2](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build2.jpg)
---
2. **Buttons**
At this step, glue the buttons into the top slots and solder resistors to their outputs. You can connect the resistor outputs together, and don't forget to attach an extra wire to the button inputs, this will later be used to connect them to the 3.3V line.
![Step4](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build4.jpg)
Next, solder all of the button outputs to the microcontroller.
Pin numbers for the buttons (and other components) are defined in the [example config](https://git.kopic.hr/tomislav/SmartCubeV1/src/branch/main/src/example_config.h), and the schematic for the [D1 Mini is here](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/schematics/esp8266.png).
You don't have to follow my exact pin definitions, but I've found this setup to be the easiest way to assemble and fit everything in. The 3-button variant is the standard. If you decide to go with 4 buttons, you'll need to define the extra pin yourself in the code.
* Button Left (PIN_BTN_L): (D6) GPIO12
* Button Middle (PIN_BTN_M): (D7) GPIO13
* Button Right (PIN_BTN_R): (D8) GPIO15
Finally, solder the GND wire to the resistor outputs and connect 3.3V to the button inputs.
![Step5](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build5.jpg)
---
3. **OLED Display**
Screw in the 2x2mm screws and hot glue the SSD1306 to the [front part of the cube](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/case/SmartCube_Front.stl) solder the 4 wires to the OLED display, make sure you have some extra length, 4-5cm should be more than enough
![Step6](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build6.jpg)
![Step7](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build7.jpg)
The OLED display must be connected via I2C on pins:
- **SDA**: D2 (GPIO4)
- **SCL**: D1 (GPIO5)
- **GND**: GND
- **VCC**: 3.3V pin or directly to the TP4056 output
![Step8](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build8.jpg)
---
4. **Buzzer**
Glue in the buzzer to the [back part of the cube](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/case/SmartCube_Back_Speaker_Side_Hole.stl) with superglue
As defined in the [example config](https://git.kopic.hr/tomislav/SmartCubeV1/src/branch/main/src/example_config.h) connect:
- the positive wire of the buzzer to the 3.3V
- the negative wire to PIN_BUZZER (D3) GPIO0
![Step9](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/build9.jpg)
---
**Battery Setup**
The battery is optional. Your SmartCube will work fine when powered via USB; however, adding one makes it portable (and much cuter).
A single 700 mAh 14250 battery lasts about 24 hours. Keep in mind there's currently no way to manually power the Cube off, it will continue running until the battery is depleted. The TP4056 prevents the cell from being completely drained and should protect it from damage.
* Solder the 14250 battery to the **TP4056 input pins**.
* Wire the **TP4056 output** to the **3.3V pin** on the D1 Mini to power the device.
* Connect the **5V output pin** from the D1 Mini to the **TP4056 input port** to allow charging through the USB data port on the ESP8266.
* *(Optional)* Add a **voltage divider** to monitor battery level on the ESP8266 **A0 pin**:
* **R1 = 220kΩ** (between battery positive and A0)
* **R2 = 56kΩ** (between A0 and GND)
This scales the battery voltage safely down for measurement (~0-0.85V).
![batt1](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/batt1.jpg)
![batt2](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/batt2.jpg)
![batt3](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/batt3.jpg)
---
## Notes
- This is still a work in progress
- Everything is pretty tightly packed in there and it's a mess. But it's not as hard to make as it looks.
![Packed](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/IMG_20241213_171725.jpg)
- Ensure all connections are secure and isolated. Hot glue is your friend.
- Test the circuit thoroughly before placing and gluing it in the enclosure.
- Battery is the trickiest part to fit in, it's best to glue the charging module directly to it and put it in the case last
For questions or additional details, feel free to reach out! I would love to hear some feedback.
Good luck and have fun :)
![Done](https://git.kopic.hr/tomislav/SmartCubeV1/raw/branch/main/hardware/pictures/IMG_20240618_203812.jpg)

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 MiB

BIN
hardware/pictures/batt1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 MiB

BIN
hardware/pictures/batt2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

BIN
hardware/pictures/batt3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 MiB

BIN
hardware/pictures/cubez.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

89
src/SmartCube/cubeDemo.h Normal file
View File

@@ -0,0 +1,89 @@
void interactiveCubeDemo() {
const int cx = SCREEN_WIDTH / 2;
const int cy = SCREEN_HEIGHT / 2;
const int size = 15; // small cube
float angle = 0;
float speed = 0.05;
bool rotating = true;
bool showVersion = false;
bool lastMiddleState = LOW; // Track previous middle button state
while (true) {
display.clearDisplay();
// Read buttons
bool leftPressed = digitalRead(PIN_BTN_L) == HIGH;
bool rightPressed = digitalRead(PIN_BTN_R) == HIGH;
bool middlePressed = digitalRead(PIN_BTN_M) == HIGH;
// Button actions
if (leftPressed) {
speed = -0.05;
beep(1000);
}
if (rightPressed) {
speed = 0.05;
beep(1000);
}
// Detect middle button press event
if (middlePressed && !lastMiddleState) {
rotating = !rotating; // toggle rotation
showVersion = !rotating; // show image if stopped
beep(1000);
}
lastMiddleState = middlePressed; // update previous state
// Draw either image or cube
if (showVersion) {
display.clearDisplay();
display.setTextSize(2);
display.setCursor(10, 0);
display.println("SmartCube");
display.setTextSize(1);
display.setCursor(40, 18);
display.println("version");
display.setCursor(52, 28);
display.println("1.1");
display.drawLine(0, 40, SCREEN_WIDTH, 40, WHITE);
display.setCursor(0, 44);
display.println("by besna_shnita");
display.setCursor(18, 55);
display.println("tomislav@kopic.hr");
} else {
if (rotating) angle += speed;
float cosA = cos(angle);
float sinA = sin(angle);
int x[8], y[8];
int vx[8] = {-size, size, size, -size, -size, size, size, -size};
int vy[8] = {-size, -size, size, size, -size, -size, size, size};
int vz[8] = {-size, -size, -size, -size, size, size, size, size};
for (int i = 0; i < 8; i++) {
float x3d = vx[i] * cosA - vz[i] * sinA;
float z3d = vx[i] * sinA + vz[i] * cosA;
float y3d = vy[i];
float factor = 50.0 / (z3d + 50.0);
x[i] = cx + x3d * factor;
y[i] = cy + y3d * factor;
}
int edges[12][2] = {
{0,1},{1,2},{2,3},{3,0},
{4,5},{5,6},{6,7},{7,4},
{0,4},{1,5},{2,6},{3,7}
};
for (int i = 0; i < 12; i++)
display.drawLine(x[edges[i][0]], y[edges[i][0]],
x[edges[i][1]], y[edges[i][1]], WHITE);
}
display.display();
delay(50);
// Exit demo if all buttons pressed
if (leftPressed && middlePressed && rightPressed) break;
}
}

View File

@@ -158,26 +158,27 @@ bool cubeWifiManager::tryConnectToSsid(const char* ssid, const char* pass) {
return false;
}
// Setup Access Point with DNS and HTTP server
void cubeWifiManager::createAP() {
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_AP);
WiFi.softAP(_ssid.c_str(), _pass.c_str(), 1, _hidden);
display.clearDisplay();
display.setCursor(0, 0);
display.println("AccessPoint created");
display.setCursor(0, 14);
display.println("SSID:");
display.setCursor(0, 24);
display.setTextSize(1);
display.setCursor(10, 0);
display.println("Access Point Ready");
display.drawLine(0, 10, 127, 10, WHITE);
display.setCursor(0, 15);
display.print("SSID: ");
display.println(_ssid.c_str());
display.setTextSize(1);
display.setCursor(0, 40);
display.setCursor(0, 28);
display.println("Config portal:");
display.setCursor(0, 50);
display.setCursor(0, 38);
display.print("http://");
display.println(WiFi.softAPIP().toString());
display.drawLine(0, 50, 127, 50, WHITE);
display.setCursor(3, 54);
display.println("Press button to skip");
display.display();
server.reset(new ESP8266WebServer(80));
@@ -195,9 +196,28 @@ void cubeWifiManager::createAP() {
dnsServer.processNextRequest();
server->handleClient();
delay(10);
if (digitalRead(PIN_BTN_L) == HIGH || digitalRead(PIN_BTN_M) == HIGH || digitalRead(PIN_BTN_R) == HIGH) {
tone(PIN_BUZZER, 1000, 100);
display.clearDisplay();
display.setCursor(0, 0);
display.println("Skipping WiFi setup...");
display.display();
delay(500);
break; // exit AP mode loop
}
}
// Clean up AP mode and return
server->stop();
WiFi.softAPdisconnect(true);
WiFi.mode(WIFI_STA); // back to station mode
}
// Redirect to AP IP if not accessed directly
bool cubeWifiManager::redirectToIp() {
if (server->hostHeader() == WiFi.softAPIP().toString()) {

View File

@@ -4,6 +4,7 @@
#include "SmartCube/cubeSound.h" // Include custom header for sound functions
#include "SmartCube/cubeButtons.h" // Include custom header for button handling functions
#include "SmartCube/cubeWifiManager.h" // Include custom header for managing WiFi connections
#include "SmartCube/cubeDemo.h" // Remove this if not using demo functions
// Initialize the OLED display with specified width, height, and reset pin
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
@@ -44,5 +45,6 @@ void setup() {
}
void loop() {
interactiveCubeDemo(); // Run the demo screen animation
cubeButtonHandler(); // Continuously check and handle button actions
}