working implementation
This commit is contained in:
parent
802b9e766b
commit
100d49b4c7
1 changed files with 122 additions and 52 deletions
174
src/main.zig
174
src/main.zig
|
|
@ -228,37 +228,55 @@ fn getDevices(allocator: std.mem.Allocator, id_token: []const u8, username: []co
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Starts recirculation for the specified device with given duration
|
/// Starts recirculation for the specified device with given duration
|
||||||
fn startRecirculation(allocator: std.mem.Allocator, id_token: []const u8, serial_number: []const u8, duration_minutes: u32) !void {
|
fn setRecirculation(allocator: std.mem.Allocator, id_token: []const u8, thing_name: []const u8, duration_minutes: ?u32) !void {
|
||||||
var client = http.Client{ .allocator = allocator };
|
var client = http.Client{ .allocator = allocator };
|
||||||
defer client.deinit();
|
defer client.deinit();
|
||||||
|
|
||||||
const url = try std.fmt.allocPrint(allocator,
|
const url = try std.fmt.allocPrint(allocator,
|
||||||
\\{s}/{s}/shadow
|
\\{s}/{s}/shadow
|
||||||
, .{ shadow_api_url, serial_number });
|
, .{ shadow_api_url, thing_name });
|
||||||
defer allocator.free(url);
|
defer allocator.free(url);
|
||||||
|
|
||||||
const body = try std.fmt.allocPrint(allocator,
|
const body = if (duration_minutes) |min|
|
||||||
\\{{"recirculation_duration":{d},"set_recirculation_enabled":true}}
|
try std.fmt.allocPrint(allocator,
|
||||||
, .{duration_minutes});
|
\\{{"recirculation_duration":"{d}","set_recirculation_enabled":true}}
|
||||||
|
, .{min})
|
||||||
|
else
|
||||||
|
try allocator.dupe(u8,
|
||||||
|
\\{"set_recirculation_enabled":false}
|
||||||
|
);
|
||||||
defer allocator.free(body);
|
defer allocator.free(body);
|
||||||
|
|
||||||
|
// std.debug.print("DEBUG: PATCH URL: {s}\n", .{url});
|
||||||
|
// std.debug.print("DEBUG: PATCH Body: {s}\n", .{body});
|
||||||
|
|
||||||
const uri = try std.Uri.parse(url);
|
const uri = try std.Uri.parse(url);
|
||||||
const auth_header = try std.fmt.allocPrint(allocator,
|
const auth_header = try std.fmt.allocPrint(allocator,
|
||||||
\\Bearer {s}
|
\\Bearer {s}
|
||||||
, .{id_token});
|
, .{id_token});
|
||||||
defer allocator.free(auth_header);
|
defer allocator.free(auth_header);
|
||||||
|
|
||||||
|
var response_buf: [4096]u8 = undefined;
|
||||||
|
var writer = std.Io.Writer.fixed(&response_buf);
|
||||||
const result = try client.fetch(.{
|
const result = try client.fetch(.{
|
||||||
.location = .{ .uri = uri },
|
.location = .{ .uri = uri },
|
||||||
.method = .PATCH,
|
.method = .PATCH,
|
||||||
.payload = body,
|
.payload = body,
|
||||||
|
.response_writer = &writer,
|
||||||
.extra_headers = &.{
|
.extra_headers = &.{
|
||||||
.{ .name = "Authorization", .value = auth_header },
|
.{ .name = "Authorization", .value = auth_header },
|
||||||
.{ .name = "Content-Type", .value = "application/json" },
|
.{ .name = "Content-Type", .value = "application/json" },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (result.status != .ok) return error.StartRecirculationFailed;
|
const response_body = response_buf[0..writer.end];
|
||||||
|
// std.debug.print("DEBUG: PATCH Response Status: {}\n", .{result.status});
|
||||||
|
// std.debug.print("DEBUG: PATCH Response Body: {s}\n", .{response_body});
|
||||||
|
|
||||||
|
if (result.status != .ok) {
|
||||||
|
std.debug.print("PATCH failed - Status: {}, Body: {s}\n", .{ result.status, response_body });
|
||||||
|
return error.StartRecirculationFailed;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const DeviceShadow = struct {
|
const DeviceShadow = struct {
|
||||||
|
|
@ -372,6 +390,10 @@ pub fn main() !void {
|
||||||
defer _ = gpa.deinit();
|
defer _ = gpa.deinit();
|
||||||
const allocator = gpa.allocator();
|
const allocator = gpa.allocator();
|
||||||
|
|
||||||
|
const args = try std.process.argsAlloc(allocator);
|
||||||
|
defer std.process.argsFree(allocator, args);
|
||||||
|
const debug_mode = args.len > 1 and std.mem.eql(u8, args[1], "--debug");
|
||||||
|
|
||||||
var stdout_buffer: [1024]u8 = undefined;
|
var stdout_buffer: [1024]u8 = undefined;
|
||||||
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
var stdout_writer = std.fs.File.stdout().writer(&stdout_buffer);
|
||||||
const stdout = &stdout_writer.interface;
|
const stdout = &stdout_writer.interface;
|
||||||
|
|
@ -393,6 +415,12 @@ pub fn main() !void {
|
||||||
defer allocator.free(auth.id_token);
|
defer allocator.free(auth.id_token);
|
||||||
defer allocator.free(auth.user_uuid);
|
defer allocator.free(auth.user_uuid);
|
||||||
try stdout.print("✓ User UUID: {s}\n\n", .{auth.user_uuid});
|
try stdout.print("✓ User UUID: {s}\n\n", .{auth.user_uuid});
|
||||||
|
|
||||||
|
if (debug_mode) {
|
||||||
|
try stdout.print("\n=== DEBUG MODE ===\n", .{});
|
||||||
|
try stdout.print("IdToken:\n{s}\n\n", .{auth.id_token});
|
||||||
|
}
|
||||||
|
|
||||||
try stdout.print("📱 Fetching devices...\n", .{});
|
try stdout.print("📱 Fetching devices...\n", .{});
|
||||||
try stdout.flush();
|
try stdout.flush();
|
||||||
var result = try getDevices(
|
var result = try getDevices(
|
||||||
|
|
@ -422,54 +450,96 @@ pub fn main() !void {
|
||||||
1 => {
|
1 => {
|
||||||
const device = result.devices[0];
|
const device = result.devices[0];
|
||||||
|
|
||||||
if (device.serial_id) |sid| {
|
if (device.serial_id == null or
|
||||||
try stdout.print("🔍 Checking recirculation status for {?s}...\n", .{device.device_name});
|
device.thing_name == null)
|
||||||
try stdout.flush();
|
{
|
||||||
|
try stderr.print("❌ thing_name and serial_id both required\n", .{});
|
||||||
var status = try getRecirculationStatus(allocator, auth.id_token, sid);
|
|
||||||
defer status.deinit();
|
|
||||||
|
|
||||||
try stdout.print("\n{f}", .{status});
|
|
||||||
|
|
||||||
const recirc_enabled = status.recirculation_enabled orelse false;
|
|
||||||
|
|
||||||
if (recirc_enabled) {
|
|
||||||
try stdout.print("\n✓ Recirculation is already active\n", .{});
|
|
||||||
} else {
|
|
||||||
try stdout.print("\n🚿 Starting 15-minute recirculation...\n", .{});
|
|
||||||
try stdout.flush();
|
|
||||||
|
|
||||||
startRecirculation(
|
|
||||||
allocator,
|
|
||||||
auth.id_token,
|
|
||||||
sid,
|
|
||||||
15,
|
|
||||||
) catch |e| {
|
|
||||||
try stderr.print("❌ Failed to start recirculation\n", .{});
|
|
||||||
try stderr.flush();
|
|
||||||
return e;
|
|
||||||
};
|
|
||||||
|
|
||||||
try stdout.print("✓ Recirculation command sent\n", .{});
|
|
||||||
try stdout.print("⏳ Waiting 20 seconds for device to respond...\n", .{});
|
|
||||||
try stdout.flush();
|
|
||||||
|
|
||||||
std.Thread.sleep(20 * std.time.ns_per_s);
|
|
||||||
|
|
||||||
var post_command_state = try getRecirculationStatus(
|
|
||||||
allocator,
|
|
||||||
auth.id_token,
|
|
||||||
sid,
|
|
||||||
);
|
|
||||||
defer post_command_state.deinit();
|
|
||||||
try stdout.print("\n{f}", .{post_command_state});
|
|
||||||
}
|
|
||||||
try stdout.flush();
|
|
||||||
} else {
|
|
||||||
try stderr.print("❌ No serial_id found for device\n", .{});
|
|
||||||
try stderr.flush();
|
try stderr.flush();
|
||||||
return error.NoSerialId;
|
return error.SerialIdAndThingNameRequired;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sid = device.serial_id.?;
|
||||||
|
const tn = device.thing_name.?;
|
||||||
|
|
||||||
|
try stdout.print("🔍 Checking recirculation status for {?s}...\n", .{device.device_name});
|
||||||
|
try stdout.flush();
|
||||||
|
|
||||||
|
var status = try getRecirculationStatus(allocator, auth.id_token, sid);
|
||||||
|
defer status.deinit();
|
||||||
|
|
||||||
|
try stdout.print("\n{f}", .{status});
|
||||||
|
|
||||||
|
if (debug_mode) {
|
||||||
|
try stdout.print("\n=== CURL COMMANDS ===\n", .{});
|
||||||
|
try stdout.print("Reset recirculation:\n", .{});
|
||||||
|
try stdout.print("curl -X PATCH '{s}/{s}/shadow' \\\n", .{ shadow_api_url, tn });
|
||||||
|
try stdout.print(" -H 'Authorization: Bearer {s}' \\\n", .{auth.id_token});
|
||||||
|
try stdout.print(" -H 'Content-Type: application/json' \\\n", .{});
|
||||||
|
try stdout.print(" -d '{{\"set_recirculation_enabled\":false}}'\n\n", .{});
|
||||||
|
|
||||||
|
try stdout.print("Start recirculation:\n", .{});
|
||||||
|
try stdout.print("curl -X PATCH '{s}/{s}/shadow' \\\n", .{ shadow_api_url, tn });
|
||||||
|
try stdout.print(" -H 'Authorization: Bearer {s}' \\\n", .{auth.id_token});
|
||||||
|
try stdout.print(" -H 'Content-Type: application/json' \\\n", .{});
|
||||||
|
try stdout.print(" -d '{{\"recirculation_duration\":15,\"set_recirculation_enabled\":true}}'\n\n", .{});
|
||||||
|
try stdout.flush();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const recirc_enabled = status.recirculation_enabled orelse false;
|
||||||
|
|
||||||
|
if (recirc_enabled) {
|
||||||
|
try stdout.print("\n✓ Recirculation is already active\n", .{});
|
||||||
|
} else {
|
||||||
|
try stdout.print("\n🚿 Starting 15-minute recirculation...\n", .{});
|
||||||
|
try stdout.flush();
|
||||||
|
|
||||||
|
if (status.set_recirculation_enabled) |en| {
|
||||||
|
if (en) {
|
||||||
|
try stdout.print("⚠️ set_recirculation_enabled is already true, resetting first...\n", .{});
|
||||||
|
try stdout.flush();
|
||||||
|
|
||||||
|
// The shadow state doesn't seem to update. The react native
|
||||||
|
// application doesn't wait, it just yolo's here, so
|
||||||
|
// we'll do the same
|
||||||
|
try setRecirculation(
|
||||||
|
allocator,
|
||||||
|
auth.id_token,
|
||||||
|
sid,
|
||||||
|
null,
|
||||||
|
);
|
||||||
|
|
||||||
|
try stdout.print("⏳ Waiting 3 seconds...\n", .{});
|
||||||
|
try stdout.flush();
|
||||||
|
std.Thread.sleep(3 * std.time.ns_per_s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setRecirculation(
|
||||||
|
allocator,
|
||||||
|
auth.id_token,
|
||||||
|
tn,
|
||||||
|
15,
|
||||||
|
) catch |e| {
|
||||||
|
try stderr.print("❌ Failed to start recirculation\n", .{});
|
||||||
|
try stderr.flush();
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
|
||||||
|
try stdout.print("✓ Recirculation command sent\n", .{});
|
||||||
|
try stdout.print("⏳ Waiting 20 seconds for device to respond...\n", .{});
|
||||||
|
try stdout.flush();
|
||||||
|
|
||||||
|
std.Thread.sleep(20 * std.time.ns_per_s);
|
||||||
|
|
||||||
|
var post_command_state = try getRecirculationStatus(
|
||||||
|
allocator,
|
||||||
|
auth.id_token,
|
||||||
|
sid,
|
||||||
|
);
|
||||||
|
defer post_command_state.deinit();
|
||||||
|
try stdout.print("\n{f}", .{post_command_state});
|
||||||
|
}
|
||||||
|
try stdout.flush();
|
||||||
},
|
},
|
||||||
else => {
|
else => {
|
||||||
try stderr.print("❌ More than one device found for user, not currently equipped to handle this\n", .{});
|
try stderr.print("❌ More than one device found for user, not currently equipped to handle this\n", .{});
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue