I was planning to make a RSS reader using this display, but I came across a weather display project I wanted to check out. (So I probably end up buying another one)
There are many questions and issues around this project using the S3.
Combining a GPS module, compass, a LED ring and some code, I want to make a little device which shows you the way to the nearest … something.
To make it completely standalone, I have to use a SIM module. (Same as I have used before) This POC will use my phone as hotspot.
The LED ring will show the direction to go.
Edit: Maybe not a LED ring but a little display.
GPS moduleCompass moduleLedring
As previously posted, I was playing with Overpass turbo. Using an API, I can use code to query this.
Arduino sends latitude, longitude to my webserver
Webserver queries API for neastest POIs and calculates distance.
Send data from webserver to arduino
Arduino uses heading data to light up direction LED (also on secondary display with distance info?) edit: and shop info
Test code for my web server to query the data
import overpy
import math
api = overpy.Overpass()
# This location will be filled with data from GPS module on Arduino.
latitude = 52.2270745 # Center latitude (e.g. Berlin)
longitude = 5.177519 # Center longitude
box_size = 0.05 # Box size in degrees (about ~5 km)
south = latitude - box_size
north = latitude + box_size
west = longitude - box_size
east = longitude + box_size
def haversine(lat1, lon1, lat2, lon2):
R = 6371 # Earth radius in km
phi1 = math.radians(lat1)
phi2 = math.radians(lat2)
d_phi = math.radians(lat2 - lat1)
d_lambda = math.radians(lon2 - lon1)
a = math.sin(d_phi / 2)**2 + math.cos(phi1) * math.cos(phi2) * math.sin(d_lambda / 2)**2
c = 2 * math.atan2(math.sqrt(a), math.sqrt(1 - a))
return R * c # Distance in kilometers
# Calculate bearing in degrees (0-360)
def bearing(lat1, lon1, lat2, lon2):
phi1 = math.radians(lat1)
phi2 = math.radians(lat2)
delta_lon = math.radians(lon2 - lon1)
x = math.sin(delta_lon) * math.cos(phi2)
y = math.cos(phi1) * math.sin(phi2) - math.sin(phi1) * math.cos(phi2) * math.cos(delta_lon)
initial_bearing = math.atan2(x, y)
compass_bearing = (math.degrees(initial_bearing) + 360) % 360 # Normalize to 0–360
return compass_bearing
# Overpass QL query
query = f"""
[out:json];
node
["shop"="alcohol"]
({south}, {west}, {north}, {east});
out body;
>;
out skel qt;
"""
try:
result = api.query(query)
# Collect and sort places by distance
places = []
for node in result.nodes:
node_lat = float(node.lat)
node_lon = float(node.lon)
distance = haversine(latitude, longitude, node_lat, node_lon)
direction = bearing(latitude, longitude, node_lat, node_lon)
name = node.tags.get("name", "Unnamed")
places.append((distance, direction, name, node_lat, node_lon))
places.sort()
print(f"Found {len(places)} alcohol-related places sorted by distance:")
for dist, dir_deg, name, lat, lon in places:
print(f"- {name} at ({lat:.5f}, {lon:.5f}) — {dist:.2f} km, {dir_deg:.0f}°")
except Exception as e:
print(f"Error: {e}")
Output:
Found 10 alcohol-related places sorted by distance:
- The Skiff at (52.22583, 5.17860) — 0.16 km, 152°
- Onzewijnen at (52.22612, 5.17045) — 0.49 km, 258°
- Gall & Gall at (52.23244, 5.19204) — 1.15 km, 59°
- Gall & Gall at (52.21536, 5.16735) — 1.48 km, 208°
- Eric's Beer Craft at (52.21549, 5.16632) — 1.50 km, 211°
- Slijterij at (52.21082, 5.15692) — 2.29 km, 218°
- Gall & Gall at (52.21590, 5.14074) — 2.80 km, 244°
- Gall & Gall at (52.25422, 5.22705) — 4.53 km, 48°
- Gall & Gall at (52.26808, 5.18348) — 4.58 km, 5°
- Il DiVino at (52.27507, 5.16414) — 5.41 km, 350°
Example using Overpass Turbo to find breweries
Other ideas
Geocaching (Thanks Vincent)
Find each other at festivals?
UPDATE
Building the hardware : First design
Screen programming (First setup)
Some test code
#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_GC9A01A.h"
// Overrule stuff
#define TFT_CS 18 // Chip select
#define TFT_DC 5 // Data/command mode
#define TFT_BL 4 // Backlight control
#define TFT_MOSI 12 // SPI Out AKA SDA
#define TFT_SCLK 13 // Clock out AKA SCL
#define TFT_MISO -1 // pin not used
#define TFT_RST 23 // Reset ################# IMPORTANT, won't work without!! Took me a hour!
// Need this changed from example also
Adafruit_GC9A01A tft(TFT_CS, TFT_DC,TFT_MOSI,TFT_SCLK,TFT_RST,TFT_MISO);
float angle = 0;
void setup() {
tft.begin();
tft.setRotation(0);
tft.fillScreen(GC9A01A_BLACK);
drawCompassFace();
}
void loop() {
drawNeedle(angle, GC9A01A_RED);
delay(1000);
drawNeedle(angle, GC9A01A_BLACK); // Erase previous needle
angle += 15;
if (angle >= 360) angle = 0;
tft.setCursor(60, 100);
tft.setTextColor(GC9A01A_WHITE); tft.setTextSize(2);
tft.println("230 Meters");
}
// Draw static compass face
void drawCompassFace() {
int cx = tft.width() / 2;
int cy = tft.height() / 2;
int radius = 100;
tft.drawCircle(cx, cy, radius, GC9A01A_WHITE);
tft.setTextColor(GC9A01A_WHITE);
tft.setTextSize(1);
tft.setCursor(cx - 3, cy - radius + 5); tft.print("N");
tft.setCursor(cx - 3, cy + radius - 10); tft.print("S");
tft.setCursor(cx - radius + 5, cy - 3); tft.print("W");
tft.setCursor(cx + radius - 10, cy - 3); tft.print("E");
}
// Draw compass needle
void drawNeedle(float angleDeg, uint16_t color) {
int cx = tft.width() / 2;
int cy = tft.height() / 2;
float angleRad = angleDeg * DEG_TO_RAD;
int x = cx + cos(angleRad) * 90;
int y = cy + sin(angleRad) * 90;
tft.drawLine(cx, cy, x, y, color);
}
substitutions:
name: usb-relay
friendly_name: "USB Relay"
default_state: "RESTORE_DEFAULT_OFF"
esphome:
name: xyusb1
friendly_name: xyusb1
esp8266:
board: esp01_1m
# Enable logging
logger:
# Enable Home Assistant API
api:
encryption:
key: "ndm8xxxxxxxxxxxxxxxxxjlvrggJv3a1BkY="
ota:
- platform: esphome
password: "12cc9xxxxxxxxxxxxxxxxfb6a01e672"
wifi:
ssid: !secret wifi_ssid
password: !secret wifi_password
# Enable fallback hotspot (captive portal) in case wifi connection fails
ap:
ssid: "Xyusb1 Fallback Hotspot"
password: "xxxxxxxxxxx"
captive_portal:
time:
- platform: homeassistant
# Blue LED
status_led:
pin:
number: GPIO16
# Relay
switch:
- platform: gpio
id: switch_relay
pin: GPIO5
# Green LED
- platform: gpio
pin: GPIO14
id: green_led
inverted: true # start on
# Switch template to link relay and green LED states
# LED is on when relay is off
- platform: template
id: relay
name: "${friendly_name}"
lambda: |-
if (id(switch_relay).state) {
return true;
} else {
return false;
}
turn_on_action:
- switch.turn_on:
id: green_led
- switch.turn_on:
id: switch_relay
turn_off_action:
- switch.turn_off:
id: green_led
- switch.turn_off:
id: switch_relay
# Button
binary_sensor:
- platform: gpio
id: hardware_button
pin:
number: GPIO04
mode: INPUT_PULLUP
inverted: True
on_press:
- switch.toggle: relay
# WiFi Signal Sensor
sensor:
- platform: wifi_signal
name: "WiFi Status"
update_interval: 60s
# Restart button
button:
- platform: restart
name: "Restart"
Reflashed my USB Volume button and added a LED-Ring.
Example is green and blue.
Funny text on box
What is a termianl assortment? LOL
Wireless Temperature/Humidity sensor for ESPHome.
Wemos D1 mini with deep sleep, voltage monitoring using A0 line. BME280 Temperature/Humidity sensor. And a 18650 battery with TP4065 battery manager. Now 3D print a little case.
3D printed a little light case for a wemos and a piece of WS2812 led strip I had lying around.
Schematic: NOTE: The resistor is 100-500 ohm (I forgot, just try) You can only use this trick for a few leds (I used 4), else you better can use the sacrifice a led to make a level shifter trick. (Wemos logic is 3.3V and the led strip is 5V)
I flashed ESPHome on the wemos using the flasher in Home Assistant.
One of the first things was reflashing the device with Momentum firmware. I’ve ordered a Wi-Fi Dev Board, so I can use Marauder.
Here are some qFlipper screenshots.
Will add pictures and info about the Wifi dev board.
Some information:
The Flipper Zero is a versatile multi-tool for geeks, hackers, and hardware enthusiasts. It is designed as a portable, open-source device with numerous capabilities for interacting with digital systems and hardware. Here’s an overview of what the Flipper Zero can do:
1. RFID and NFC Communication
Read and Emulate: Supports RFID cards (low-frequency 125 kHz) and NFC cards (high-frequency 13.56 MHz). It can read, emulate, and clone certain types of RFID/NFC tags, such as access cards and contactless payment cards (within legal limits).
Protocols Supported: Includes MIFARE, HID Prox, and others used in access control systems.
2. Sub-GHz Radio Transmission
Works with a wide range of sub-GHz frequencies (300-900 MHz) used in garage door openers, key fobs, IoT devices, and wireless sensors.
Transmit and Analyze: It can capture, analyze, and even replay radio signals for research and testing purposes.
3. Infrared (IR) Control
Universal Remote: The Flipper Zero has an IR transmitter/receiver that allows it to control TVs, air conditioners, and other IR-enabled devices.
It can learn IR commands and replay them for universal control.
4. GPIO Pins for Custom Projects
Hardware Hacking: Provides GPIO (General Purpose Input/Output) pins for connecting to external hardware.
You can use the GPIO pins to interact with sensors, control relays, or debug devices like routers or microcontrollers.
5. Bluetooth and Wi-Fi (with Modules)
Bluetooth LE: Built-in Bluetooth Low Energy support allows communication with BLE-enabled devices.
Wi-Fi: Optional Wi-Fi dev board attachment (like the ESP8266 or ESP32) expands its capabilities for network penetration testing or IoT device research.
6. BadUSB and HID Attacks
Emulate USB Devices: Can act as a USB keyboard or mouse for automating tasks or security testing.
Useful for penetration testing with scripts (similar to tools like Rubber Ducky).
7. Universal Debugging
The Flipper can debug and interact with devices via UART, SPI, and I2C protocols, making it a powerful tool for developers and hackers.
8. Tamagotchi Mode
Includes a fun “pet” feature where you care for and interact with a digital creature that grows and evolves based on how you use the device.
9. Extensible and Open Source
The Flipper Zero’s firmware is open-source, allowing developers to modify and expand its capabilities.
It supports custom plugins, applications, and firmware modifications.
10. Signal Analysis and Replay
Capture, analyze, and replay signals (e.g., remote controls) for testing and research.
Legal Disclaimer: Using these features responsibly and within the bounds of the law is crucial.
Common Uses
Security auditing and penetration testing.
Reverse engineering and debugging hardware.
Researching IoT devices and wireless communications.
Fun DIY projects and learning electronics.
The Flipper Zero is a powerful tool, but its legality depends on how it is used. Be sure to respect laws and ethical guidelines when exploring its capabilities.
I reversed engineered the workings, and created a python upload script to push images.
Original workings are a mess. Per 4 bit of color, high-low switched in a byte. Black and red separated. Using a till p encoding over curl commands.
My implementation uses a python script called as:
python3 epaper-pusher.py ~/Downloads/Untitled.png
http://10.1.0.99/EPDI_
30 times something like
http://10.1.0.99/ppppppppppppppppppppppppppppppppppppppppppppppppppppppaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppiodaLOAD_
http://10.1.0.99/NEXT_
30 times something like
http://10.1.0.99/pbcdefghijjjjjjffffffoooooooaaabbbbbbeeeedddppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppppiodaLOAD_
http://10.1.0.99/SHOW_
NOTES:
a = 0000
-
-
-
p = 1111 = 15
30 lines with 1000 bytes ( ending with iodaLOAD_ )
black pixels
first block 1
second block 0
red pixels
first block 0
second block 1
white pixels
first block 1
second block 1
PIXEL Example
RBRB
BWBW
First block
1010 - letter K
0101 - Letter F - second nibble = white
Second block
0101 - Letter F
1111 - Letter P - second nibble white
Code
from PIL import Image
import numpy
import requests
url="http://10.1.0.99/"
black_pixels = numpy.zeros((400,300))
red_pixels = numpy.zeros((400,300))
def classify_pixel_color(pixel):
"""
Classify a pixel as black, white, or red.
"""
r, g, b = pixel[:3] # Ignore alpha if present
# Define thresholds for classification
if r < 128 and g < 128 and b < 128:
return 'black'
elif r > 200 and g > 200 and b > 200:
return 'white'
elif r > 128 and g < 100 and b < 100:
return 'red'
else:
return None
def process_image(image_path):
"""
Process the image and classify its pixels into black, white, or red.
"""
image = Image.open(image_path)
image = image.convert("RGB") # Ensure the image is in RGB mode
width, height = image.size
pixel_data = image.load()
color_counts = {'black': 0, 'white': 0, 'red': 0}
for y in range (0, 299):
for x in range (0, 399):
black_pixels[x][y] = 0
red_pixels[x][y] = 0
for y in range(299):
for x in range(399):
color = classify_pixel_color(pixel_data[x, y])
if color:
color_counts[color] += 1
if color == 'black':
black_pixels[x][y] = 1;
if color == 'red':
red_pixels[x][y] = 1;
if color == 'white':
black_pixels[x][y] = 1;
red_pixels[x][y] = 1;
return color_counts, black_pixels, red_pixels
def number_to_letter(num):
"""
Translates a number from 0 to 15 into a corresponding letter (a-p).
Args:
num (int): The number to translate.
Returns:
str: The corresponding letter (a-p).
"""
if 0 <= num <= 15:
return chr(ord('a') + num)
else:
raise ValueError("Number must be between 0 and 15, inclusive.")
def print_array_in_chunks(array, chunk_size=1001):
current_chunk = ""
for item in array:
# Convert item to string and add to the current chunk
item_str = str(item)
if len(current_chunk) + len(item_str) + 1 > chunk_size:
# Print the current chunk and reset it
current_chunk += "iodaLOAD_"
try:
requests.get(url + current_chunk, verify=False)
if not response.content: # Equivalent to expecting an empty reply
pass
except requests.exceptions.RequestException as e:
# Catch any request-related errors
pass
current_chunk = item_str
else:
# Append the item to the current chunk
current_chunk += (item_str)
current_chunk += "iodaLOAD_"
# Print any remaining items in the chunk
if current_chunk:
try:
requests.get(url + current_chunk, verify=False)
if not response.content: # Equivalent to expecting an empty reply
pass
except requests.exceptions.RequestException as e:
# Catch any request-related errors
pass
def switch_in_pairs(arr):
# Loop through the array with a step of 2
for i in range(0, len(arr) - 1, 2):
# Swap values at index i and i+1
arr[i], arr[i + 1] = arr[i + 1], arr[i]
return arr
if __name__ == "__main__":
import sys
if len(sys.argv) < 2:
print("Usage: python3 script.py <image_path>")
sys.exit(1)
image_path = sys.argv[1]
try:
color_counts, black_pixels, red_pixels = process_image(image_path)
try:
requests.get(url + "EPDI_" , verify=False)
if not response.content: # Equivalent to expecting an empty reply
pass
except requests.exceptions.RequestException as e:
# Catch any request-related errors
pass
lines=[]
for y in range(300):
for x in range(0,399,4):
first = red_pixels[x][y]
second = red_pixels[x+1][y]
thirth = red_pixels[x+2][y]
fourth = red_pixels[x+3][y]
nibble = 0
if (first == 1):
nibble = nibble + 8
if (second == 1):
nibble = nibble + 4
if (thirth == 1):
nibble = nibble + 2
if (fourth == 1):
nibble = nibble + 1
lines.append(number_to_letter(nibble))
switched_array = switch_in_pairs(lines)
print_array_in_chunks(switched_array)
try:
requests.get(url + "NEXT_" , verify=False)
if not response.content: # Equivalent to expecting an empty reply
pass
except requests.exceptions.RequestException as e:
# Catch any request-related errors
pass
lines=[]
for y in range(300):
for x in range(0,399,4):
first = black_pixels[x][y]
second = black_pixels[x+1][y]
thirth = black_pixels[x+2][y]
fourth = black_pixels[x+3][y]
nibble = 0
if (first == 1):
nibble = nibble + 8
if (second == 1):
nibble = nibble + 4
if (thirth == 1):
nibble = nibble + 2
if (fourth == 1):
nibble = nibble + 1
lines.append(number_to_letter(nibble))
switched_array = switch_in_pairs(lines)
print_array_in_chunks(switched_array)
try:
requests.get(url + "SHOW_" , verify=False)
if not response.content: # Equivalent to expecting an empty reply
pass
except requests.exceptions.RequestException as e:
# Catch any request-related errors
pass
except Exception as e:
pass
A while ago, I bought a small Dehumidifier for my wine cellar. I liked it a lot, so I bought another for our bedroom.
I saw some posts about people asking which Dehumidifier is supported by Home Assistant. This one is. The “Eeese Otto Dehumidifier”
This works with the LocalTuya integration.
There are many examples how to integrate LocalTuya in HA which can be found easily using a search on the net. So, I’m not going to explain that.
I could not find a configuration example, that’s why I’ll post that part here.
Pre config:
Install App on phone to connect Tuya device to cloud (one time only) You need this to extract the localkey
Add a developer account to https://eu.platform.tuya.com/ (Enable devices and change from Read to Control) (Get localkey from API Explorer, here is also a hint to be found about the entities) See below pictures
Install LocalTuya to HA
End result after config
Gallery of config steps
Developer website information, where to find your credentials. (And a list of entities)
"If something is worth doing, it's worth overdoing."