Skip to content

Instantly share code, notes, and snippets.

@shahonseven
Last active December 23, 2025 10:22
Show Gist options
  • Select an option

  • Save shahonseven/13c19549ebe70286ad8cfadd87762042 to your computer and use it in GitHub Desktop.

Select an option

Save shahonseven/13c19549ebe70286ad8cfadd87762042 to your computer and use it in GitHub Desktop.
alias: Washing Machine State Notification
description: ""
triggers:
- entity_id:
- sensor.front_load_washer_run_state
for:
hours: 0
minutes: 0
seconds: 30
trigger: state
conditions: []
actions:
- choose:
- conditions:
- condition: and
conditions:
- condition: state
entity_id: sensor.front_load_washer_run_state
state: "-"
- condition: state
entity_id: sensor.front_load_washer_time_remain
state: "0:00:00"
sequence:
- action: rest_command.set_geekmagic_theme
metadata: {}
data:
theme: 5
default:
- action: rest_command.set_geekmagic_theme
metadata: {}
data:
theme: 3
- delay:
hours: 0
minutes: 0
seconds: 0
milliseconds: 30
- action: rest_command.update_geekmagic_washing_machine_status
metadata: {}
data:
status: "{{ states('sensor.front_load_washer_run_state') }}"
mode: single
rest_command:
set_geekmagic_theme:
url: http://192.168.0.139/set?theme={{ theme }}
method: GET
update_geekmagic_washing_machine_status:
url: https://192.168.0.175/washing-machine-status-updater.php?status={{ status }}
method: GET
<?php
// 1. CHANGE: Set the content-type to jpeg
header('Content-Type: image/jpeg');
// 2. Configuration
$width = 240;
$height = 240;
$status = isset($_GET['status']) ? strtolower($_GET['status']) : 'idle';
$status = filter_var($status, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
// 3. Create the canvas
$im = imagecreatetruecolor($width, $height);
// 4. Define Colors
$white = imagecolorallocate($im, 255, 255, 255);
$bg_gray = imagecolorallocate($im, 240, 240, 240);
$machine_w = imagecolorallocate($im, 250, 250, 250);
$outline = imagecolorallocate($im, 100, 100, 100);
$panel_gray = imagecolorallocate($im, 200, 200, 200);
$black = imagecolorallocate($im, 0, 0, 0);
// Status Specific Colors
$idle_gray = imagecolorallocate($im, 50, 50, 50);
$wash_blue = imagecolorallocate($im, 100, 180, 255);
$rinse_blue = imagecolorallocate($im, 135, 206, 250);
$spin_blue = imagecolorallocate($im, 50, 100, 200);
$dry_orange = imagecolorallocate($im, 255, 140, 0);
$detect_purple = imagecolorallocate($im, 147, 112, 219);
$pause_amber = imagecolorallocate($im, 255, 191, 0);
$done_green = imagecolorallocate($im, 100, 200, 100);
$error_red = imagecolorallocate($im, 220, 80, 80);
// Enable anti-aliasing
imageantialias($im, true);
// 5. Draw Basic Structure (Background & Body)
imagefilledrectangle($im, 0, 0, $width, $height, $bg_gray);
$m_x = 40; $m_y = 20;
$m_w = 160; $m_h = 200;
// Body
imagefilledrectangle($im, $m_x, $m_y, $m_x + $m_w, $m_y + $m_h, $machine_w);
imagerectangle($im, $m_x, $m_y, $m_x + $m_w, $m_y + $m_h, $outline);
// Control Panel
imagefilledrectangle($im, $m_x + 5, $m_y + 5, $m_x + $m_w - 5, $m_y + 40, $panel_gray);
// Knob
imagefilledellipse($im, $m_x + 30, $m_y + 22, 20, 20, $white);
imageellipse($im, $m_x + 30, $m_y + 22, 20, 20, $outline);
// 6. Determine Logic for Status
$status_text = "IDLE";
$window_color = $idle_gray;
$text_color = $done_green; // Default LED color
// Visual Flags
$show_bubbles = false;
$show_spin_lines = false;
$show_rain = false;
$show_heat = false;
$show_target = false;
$show_pause = false;
switch ($status) {
case 'pause':
$status_text = "PAUSE";
$window_color = $pause_amber;
$text_color = $pause_amber;
$show_pause = true;
break;
case 'detecting load level':
$status_text = "LOAD";
$window_color = $detect_purple;
$show_target = true;
$text_color = $white;
break;
case 'washing':
$status_text = "WASH";
$window_color = $wash_blue;
$show_bubbles = true;
break;
case 'rinsing':
$status_text = "RINSE";
$window_color = $rinse_blue;
$show_rain = true;
break;
case 'fresh care':
$status_text = "FRESH CARE";
$window_color = $spin_blue;
$show_spin_lines = true;
break;
case 'spinning':
$status_text = "SPIN";
$window_color = $spin_blue;
$show_spin_lines = true;
break;
case 'drying':
$status_text = "DRY";
$window_color = $dry_orange;
$text_color = $dry_orange;
$show_heat = true;
break;
case 'finished':
$status_text = "DONE";
$window_color = $done_green;
break;
case 'error':
$status_text = "ERR!";
$window_color = $error_red;
$text_color = $error_red;
break;
case 'off':
$status_text = "OFF";
$window_color = $idle_gray;
break;
default:
$status_text = "IDLE";
$window_color = $idle_gray;
break;
}
// 7. Draw The Door
$center_x = $width / 2;
$center_y = $height / 2 + 20;
$door_radius = 100;
$window_radius = 80;
// Door Frame
imagefilledellipse($im, $center_x, $center_y, $door_radius, $door_radius, $panel_gray);
imageellipse($im, $center_x, $center_y, $door_radius, $door_radius, $outline);
// Glass Window (Inner)
imagefilledellipse($im, $center_x, $center_y, $window_radius, $window_radius, $window_color);
// 8. Render Status Effects
// EFFECT: Pause (Two Vertical Bars)
if ($show_pause) {
imagefilledrectangle($im, $center_x - 20, $center_y - 25, $center_x - 5, $center_y + 25, $white);
imagefilledrectangle($im, $center_x + 5, $center_y - 25, $center_x + 20, $center_y + 25, $white);
}
// EFFECT: Detecting Load (Crosshair)
if ($show_target) {
imagesetthickness($im, 2);
imageline($im, $center_x - 30, $center_y, $center_x + 30, $center_y, $white);
imageline($im, $center_x, $center_y - 30, $center_x, $center_y + 30, $white);
imageellipse($im, $center_x, $center_y, 25, 25, $white);
imagefilledellipse($im, $center_x - 20, $center_y - 20, 4, 4, $white);
imagefilledellipse($im, $center_x + 20, $center_y + 20, 4, 4, $white);
imagesetthickness($im, 1);
}
// EFFECT: Washing Bubbles
if ($show_bubbles) {
for($i=0; $i<12; $i++) {
$bx = rand($center_x - 30, $center_x + 30);
$by = rand($center_y - 10, $center_y + 35);
$bs = rand(5, 14);
imagefilledellipse($im, $bx, $by, $bs, $bs, $white);
}
}
// EFFECT: Rinsing (Falling water lines)
if ($show_rain) {
imagesetthickness($im, 2);
for($i=0; $i<15; $i++) {
$rx = rand($center_x - 30, $center_x + 30);
$ry = rand($center_y - 30, $center_y + 30);
imageline($im, $rx, $ry, $rx, $ry + 10, $white);
}
imagesetthickness($im, 1);
}
// EFFECT: Spinning (Motion Blur Arcs)
if ($show_spin_lines) {
imagesetthickness($im, 3);
imagearc($im, $center_x, $center_y, $window_radius-20, $window_radius-20, 0, 120, $white);
imagearc($im, $center_x, $center_y, $window_radius-20, $window_radius-20, 180, 300, $white);
imagesetthickness($im, 1);
}
// EFFECT: Drying (Rising Heat Waves)
if ($show_heat) {
imagesetthickness($im, 2);
$offsets = [-20, 0, 20];
foreach($offsets as $offset) {
$start_x = $center_x + $offset;
for ($y = $center_y + 20; $y > $center_y - 30; $y -= 5) {
$x_shift = ($y % 20 < 10) ? 3 : -3;
imageline($im, $start_x + $x_shift, $y, $start_x - $x_shift, $y - 5, $white);
}
}
imagesetthickness($im, 1);
}
// 9. Glass Reflection
imagearc($im, $center_x, $center_y, $window_radius - 10, $window_radius - 10, 200, 260, $white);
// 10. Draw LCD Text
imagefilledrectangle($im, $m_x + 80, $m_y + 12, $m_x + 140, $m_y + 32, $black);
$font = 4;
$font_width = imagefontwidth($font);
$font_height = imagefontheight($font);
$text_width = strlen($status_text) * $font_width;
$text_x = ($m_x + 80) + ((60 - $text_width) / 2);
$text_y = ($m_y + 12) + ((20 - $font_height) / 2);
imagestring($im, $font, (int)$text_x, (int)$text_y, $status_text, $text_color);
// 11. CHANGE: Output as JPEG with 90% quality
imagejpeg($im, NULL, 90);
imagedestroy($im);
<?php
// 1. Capture and Sanitize the Input
// We use a default value if 'status' is not provided.
$status = isset($_GET['status']) ? $_GET['status'] : 'idle';
$status = filter_var($status, FILTER_SANITIZE_FULL_SPECIAL_CHARS);
// Important: urlencode ensures special characters don't break the URL
$encodedStatus = urlencode($status);
// 2. Define Configuration
$sourceUrl = "http://10.0.1.175/?status={$encodedStatus}";
$destinationUrl = "http://10.0.1.174/doUpload?dir=%2Fimage%2F";
$uploadFileName = "washing_machine_status.jpg";
// Define a temporary path to store the downloaded file
$tempFilePath = sys_get_temp_dir() . DIRECTORY_SEPARATOR . $uploadFileName;
// --- STEP 1: Download the Image ---
$chDownload = curl_init($sourceUrl);
$fp = fopen($tempFilePath, 'wb');
curl_setopt($chDownload, CURLOPT_FILE, $fp);
curl_setopt($chDownload, CURLOPT_HEADER, 0);
curl_setopt($chDownload, CURLOPT_FOLLOWLOCATION, true);
// Execute download
curl_exec($chDownload);
$downloadHttpCode = curl_getinfo($chDownload, CURLINFO_HTTP_CODE);
curl_close($chDownload);
fclose($fp);
if ($downloadHttpCode !== 200) {
die("Error: Failed to download image from source. HTTP Code: $downloadHttpCode");
}
// --- STEP 2: Upload the Image ---
// Prepare the file for upload using CURLFile (Standard for PHP 5.5+)
// The MIME type is set to image/jpeg
$cFile = new CURLFile($tempFilePath, 'image/jpeg', $uploadFileName);
// NOTE: You must verify the input name the receiving server expects.
// It is often 'file', 'image', or 'data'. We are assuming 'file' here.
$postData = [
'file' => $cFile
];
$chUpload = curl_init();
curl_setopt($chUpload, CURLOPT_URL, $destinationUrl);
curl_setopt($chUpload, CURLOPT_POST, 1);
curl_setopt($chUpload, CURLOPT_POSTFIELDS, $postData);
curl_setopt($chUpload, CURLOPT_RETURNTRANSFER, true);
// Execute upload
$response = curl_exec($chUpload);
$uploadHttpCode = curl_getinfo($chUpload, CURLINFO_HTTP_CODE);
if (curl_errno($chUpload)) {
echo 'Upload Error: ' . curl_error($chUpload);
} else {
echo "Upload Complete.";
}
curl_close($chUpload);
// --- Cleanup ---
// Delete the temporary file
if (file_exists($tempFilePath)) {
unlink($tempFilePath);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment