Below is my python script to push messages via pushover to my phone.
It’s being run from a cron during the day.
CODE
import csv
import datetime
import requests
# configure own creds
PUSHOVER_USER_KEY = 'keykeykeykeykeykeykeykey'
PUSHOVER_API_TOKEN = 'tokentokentokentokentokentokentoken'
CSV_FILE = '/data/notifications.csv'
def send_pushover_notification(message):
url = "https://api.pushover.net/1/messages.json"
payload = {
"token": PUSHOVER_API_TOKEN,
"user": PUSHOVER_USER_KEY,
"message": message
}
response = requests.post(url, data=payload)
if response.status_code != 200:
print("Failed to send notification:", response.text)
def check_and_notify():
today = datetime.date.today()
with open(CSV_FILE, newline='') as csvfile:
reader = csv.DictReader(csvfile)
for row in reader:
try:
day = int(row['day'])
month = int(row['month'])
if today.day == day and today.month == month:
send_pushover_notification(row['message'])
except ValueError:
continue
if __name__ == "__main__":
check_and_notify()
notifications.csv file
day,month,message
1,1,Birthday of a new year
16,05,Project Deadline
16,05,Test2 (blah) 2
7,3,Glorious bastard Rik Mayall birthday
27,3,International whisky day
Nice to haves (didn’t implement because i’m a lazy bastard)
3rd Saturday every may
Getting dates or updates from another app
Selecting Pushover device, level of alertness .. etc
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
Having my own business means having a more professional electronics lab is a must. So I’m moving from the attic to our outside workshop. That also means I have to make our Music Studio smaller.
So moving, printing a lot on my new 3D printer and designing EuroCards.
Part of the Address decoding eurocard with din41612.
Above card will hold two address decodes parts, selectable using jumpers. ( Old skool TTL using 74xx and a new solution using ATF22V10.
We like Low Poly models, so I printed one using marble PLA.
In the back my 100yr old highhat from my Grandfather (moleskin)
I’ve cleaned my old 3D printer, and I am planning to convert this printer to a 2D plotter and a CNC machine.
I’ve already printed a pen holder and a dremel holder. (The filament head will be removed)
I’m working on a Gcode writer to plot drawings using a pen, or using a Gyro-cut knife to cut paper. And the biggest project using this old 3D printer, a CNC machine!
Test Code:
import time
import serial
arduino = serial.Serial('/dev/ttyUSB0', 115200, timeout=.1)
# Motor stuff
arduino.write(str.encode("M84 X Y Z S12000\r\n"))
arduino.write(str.encode("M92 X160 Y160 Z800\r\n"))
# Extrude fix
arduino.write(str.encode("G92 E0\r\n"))
# Go home
arduino.write(str.encode("G28\r\n"))
# Move to x,y,z
arduino.write(str.encode("G1 Z90 X50 Y50\r\n"))
# Wait
arduino.write(str.encode("M400\r\n"))
Sin wave fun:
import time
import serial
import math
from time import sleep
arduino = serial.Serial('/dev/ttyUSB0', 115200, timeout=.1)
arduino.write(str.encode("M84 X Y Z S12000\r\n"))
arduino.write(str.encode("M92 X160 Y160 Z800\r\n"))
arduino.write(str.encode("G92 E0\r\n"))
arduino.write(str.encode("G28\r\n"))
arduino.write(str.encode("M220 S100\r\n"))
arduino.write(str.encode("G1 Z10 X60 Y60\r\n"))
arduino.write(str.encode("M400\r\n"))
sleep(10)
count = 0
while True:
newx=(math.sin(math.radians(count))*50)+60
newy=(math.cos(math.radians(count))*50)+60
newz=(math.cos(math.radians(count))*10)+20
count = count + 1
mystring="G1 Z" + str(newz) + " X" + str(newx) + " Y" + str(newy) + "\r\n"
print(mystring)
arduino.write(str.encode(mystring))
arduino.write(str.encode("M400\r\n"))
# Not waiting for answer yet
print(newx)
sleep(0.1)
Socket connect to server, enter number and get reply test.
server.py
import socket
import threading
# Define the host and port
HOST = '0.0.0.0' # Localhost (change as needed)
PORT = 65432 # Port to listen on (non-privileged ports are > 1023)
# Function to handle each client connection
def handle_client(conn, addr):
print(f"Connected by {addr}")
# Send a thank you message to the client upon connection
thank_you_message = "Thank you for connecting! Please enter a number:\n"
conn.sendall(thank_you_message.encode('utf-8'))
while True:
try:
data = conn.recv(1024)
if not data:
break
# Decode the received data
received_number = data.decode('utf-8').strip()
print(f"Received from {addr}: {received_number}")
# Try to convert the received data to an integer
try:
number = int(received_number)
response = f"The double of {number} is {number * 2}\n"
except ValueError:
response = "Please enter a valid number.\n"
# Send the response back to the client
conn.sendall(response.encode('utf-8'))
except ConnectionResetError:
print(f"Connection with {addr} lost.")
break
conn.close()
print(f"Connection with {addr} closed.")
# Function to start the server and listen for connections
def start_server():
# Create a socket object
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Bind the socket to the host and port
server.bind((HOST, PORT))
# Start listening with a maximum backlog of 5 connections
server.listen(5)
print(f"Server listening on {HOST}:{PORT}")
while True:
# Accept a new connection
conn, addr = server.accept()
# Create a new thread to handle the client connection
client_thread = threading.Thread(target=handle_client, args=(conn, addr))
client_thread.start()
# Run the server
if __name__ == "__main__":
start_server()
python-client.py
import socket
# Define the server host and port
HOST = 'IPNUMBERSERVER' # The server's hostname or IP address
PORT = 65432 # The port used by the server
def start_client():
# Create a socket object
client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Connect to the server
client.connect((HOST, PORT))
# Receive and print the welcome message from the server
welcome_message = client.recv(1024).decode('utf-8')
print(welcome_message)
while True:
# Enter a number and send it to the server
number = input("Enter a number (or type 'exit' to quit): ")
if number.lower() == 'exit':
print("Closing connection...")
break
client.sendall(number.encode('utf-8'))
# Receive the response from the server and print it
response = client.recv(1024).decode('utf-8')
print(response)
# Close the connection after the loop ends
client.close()
# Run the client
if __name__ == "__main__":
start_client()
arduino-client.ino
#include <ESP8266WiFi.h> // For ESP8266
//#include <WiFi.h> // For ESP32
// Replace with your network credentials
const char* ssid = "your_SSID"; // Replace with your network SSID (name)
const char* password = "your_PASSWORD"; // Replace with your network password
// Define the server's IP address and port
const char* host = "192.168.1.100"; // Replace with your server's IP address
const int port = 65432; // Server port
WiFiClient client;
void setup() {
Serial.begin(115200);
delay(10);
// Connect to WiFi
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print(".");
}
Serial.println();
Serial.println("WiFi connected.");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Connect to the server
Serial.print("Connecting to server at ");
Serial.print(host);
Serial.print(":");
Serial.println(port);
if (client.connect(host, port)) {
Serial.println("Connected to server!");
// Wait for the welcome message from the server
while (client.available() == 0);
// Read and print the welcome message
while (client.available()) {
char c = client.read();
Serial.print(c);
}
} else {
Serial.println("Connection failed.");
}
}
void loop() {
// Check if connected to the server
if (client.connected()) {
// Check if there is any serial input from the user
if (Serial.available() > 0) {
String input = Serial.readStringUntil('\n');
input.trim();
if (input.equalsIgnoreCase("exit")) {
Serial.println("Closing connection...");
client.stop(); // Disconnect from the server
while (true); // Stop the loop
}
// Send the number to the server
client.println(input);
// Wait for the server's response
while (client.available() == 0);
// Read and print the server's response
while (client.available()) {
char c = client.read();
Serial.print(c);
}
}
} else {
Serial.println("Disconnected from server.");
while (true); // Stop the loop
}
}
"If something is worth doing, it's worth overdoing."