### Controller Settings Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md These examples illustrate the bitmask configuration for controller settings, including swapping top button outlet assignment and disabling standby lighting. Constraints apply regarding device state and lockout periods. ```plaintext 0x00 = Normal outlet assignment, standby lighting on (default) 0x01 = Outlets swapped, standby lighting on 0x02 = Normal outlet assignment, standby lighting off 0x03 = Outlets swapped, standby lighting off ``` -------------------------------- ### Min/Max Temperature Limit Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Examples showing valid and invalid configurations for the secondary temperature limit (minMaxTemperatureLimit) in relation to minimum and maximum temperatures. ```text minimumTemperature = 200 (20.0°C) minMaxTemperatureLimit = 380 (38.0°C) [default] maximumTemperature = 450 (45.0°C) // Valid: 20.0 ≤ 38.0 ≤ 45.0 ``` ```text minimumTemperature = 380 (38.0°C) minMaxTemperatureLimit = 380 (38.0°C) maximumTemperature = 450 (45.0°C) // Valid: 38.0 ≤ 38.0 ≤ 45.0 ``` ```text minimumTemperature = 450 (45.0°C) minMaxTemperatureLimit = 380 (38.0°C) maximumTemperature = 450 (45.0°C) // INVALID: 45.0 > 38.0 violates constraint ``` -------------------------------- ### StartPreset Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Activates a preset, starting water flow with the specified preset settings. ```APIDOC ## StartPreset ### Description Activate a preset, starting water flow with preset settings. ### Command ID 0xb1 ### Payload Length 1 byte ### Restricted No ### Payload Structure ``` [ presetSlot ] ``` #### Parameters | Field | Type | Size | Description | |---|---|---|---| | presetSlot | byte | 1 | Preset slot to activate (0-15) | ### Response Notification Type ControlsOperated ### Response Details 11-byte payload with state after preset activation #### Payload Structure ``` [ operationStatus, runningState, targetTemperature (2B), actualTemperature (2B), outlet1FlowRate, outlet2FlowRate, secondsRemaining (2B), updateCounter ] ``` See [ControlsOperated Notification](notifications.md#controlsoperated) for field details. ### Example Usage ```c uint8_t payload[1] = {presetSlot}; // Send command, expect ControlsOperated notification ``` ``` -------------------------------- ### Quick Rinse Preset Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Configuration details for a typical 'Quick Rinse' preset. ```text presetName = "Quick Rinse" targetTemperature = 0x00FA (25.0°C) flowRate = 0x64 duration = 0x0C (120 seconds = 2 minutes) outletsEnabled = 0x03 (both) ``` -------------------------------- ### Minimum Temperature Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Examples for setting the minimum safe temperature limit for an outlet. The value is divided by 10 to get the temperature in Celsius. ```text 0x0020 (32) = 3.2°C 0x0032 (50) = 5.0°C 0x00FA (250) = 25.0°C 0x00EC (236) = 23.6°C ``` -------------------------------- ### Maximum Duration Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Examples demonstrating how to set the maximum continuous run duration for an outlet in seconds. The value is multiplied by 10 to get the actual duration. ```text 0x0A (10) = 100 seconds 0x14 (20) = 200 seconds 0x3C (60) = 600 seconds (10 minutes) 0x78 (120) = 1200 seconds (20 minutes) 0xC0 (192) = 1920 seconds (32 minutes) ``` -------------------------------- ### Maximum Temperature Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Examples for setting the maximum safe temperature limit for an outlet. The value is divided by 10 to get the temperature in Celsius. ```text 0x0190 (400) = 40.0°C 0x01C2 (450) = 45.0°C 0x01F4 (500) = 50.0°C 0x0226 (550) = 55.0°C ``` -------------------------------- ### Morning Shower Preset Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Configuration details for a typical 'Morning Shower' preset. ```text presetName = "Morning Shower" targetTemperature = 0x017C (38.0°C) flowRate = 0x64 duration = 0x78 (1200 seconds = 20 minutes) outletsEnabled = 0x03 (both) ``` -------------------------------- ### Valid Temperature Configurations Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/errors.md Illustrates valid configurations for minimum, maximum, and limit temperatures in Celsius, encoded as integers multiplied by 10. ```text minimumTemperature = 200 (20.0°C) minMaxTemperatureLimit = 380 (38.0°C) maximumTemperature = 450 (45.0°C) // Valid: 20.0 ≤ 38.0 ≤ 45.0 minimumTemperature = 180 (18.0°C) minMaxTemperatureLimit = 180 (18.0°C) maximumTemperature = 450 (45.0°C) // Valid: 18.0 ≤ 18.0 ≤ 45.0 ``` -------------------------------- ### Kids Bath Preset Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Configuration details for a typical 'Kids Bath' preset. ```text presetName = "Kids Bath" targetTemperature = 0x0122 (29.0°C) flowRate = 0x64 duration = 0x24 (360 seconds = 6 minutes) outletsEnabled = 0x03 (both) ``` -------------------------------- ### Command Chunking Implementation Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/SUMMARY.txt Illustrates how to implement command chunking for sending large messages that exceed the Bluetooth MTU. This example is relevant for the implementation guide. ```c // Example of command chunking logic (conceptual) // Assumes a function `send_bluetooth_packet(data, length)` exists #define MAX_PAYLOAD_SIZE 20 // Example MTU limit void send_chunked_command(const uint8_t* command_payload, size_t payload_size) { uint8_t buffer[MAX_PAYLOAD_SIZE]; size_t offset = 0; while (offset < payload_size) { size_t chunk_size = payload_size - offset; if (chunk_size > MAX_PAYLOAD_SIZE) { chunk_size = MAX_PAYLOAD_SIZE; } // Construct the packet with chunking information (e.g., sequence number, total chunks) // For simplicity, this example just sends raw data chunks. memcpy(buffer, command_payload + offset, chunk_size); // send_bluetooth_packet(buffer, chunk_size); offset += chunk_size; } // Handle finalization or acknowledgments if necessary } ``` -------------------------------- ### StartPreset Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/README.md Starts a preset. The payload contains the preset slot number to initiate. ```plaintext StartPreset 0xb1 1 [ presetSlot ] ``` -------------------------------- ### Client Name Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/types.md Illustrates the in-memory format for a client name, null-padded to 20 bytes. UTF-8 encoding is supported. ```text "MyShowerApp\0\0\0\0\0\0\0\0\0" 4D 79 53 68 6F 77 65 72 41 70 70 00 00 00 00 00 00 00 00 00 ``` -------------------------------- ### Initial BLE Connection and Setup Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/README.md Sequence for establishing the first BLE connection, including scanning, connecting, subscribing to notifications, pairing, and storing device-specific information. ```text 1. BLE Scan → Find "Mira N86Sd: *" device 2. Connect → Open BLE connection 3. Subscribe → Enable notifications on CHARACTERISTIC_NOTIFICATIONS 4. Pair → Send Pair command with random clientId + clientName → Device responds with allocated clientSlot 5. Store → Save clientSlot + clientId to persistent storage ``` -------------------------------- ### Preset Name Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/types.md Demonstrates the in-memory structure of a preset name, null-padded within a 24-byte field. Supports UTF-8 encoding. ```text "Morning Shower\0\0" 4D 6F 72 6E 69 6E 67 20 53 68 6F 77 65 72 00 00 ``` -------------------------------- ### Pair Command Example in C Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Demonstrates building the payload for the Pair command, including generating a client ID and client name. The allocated clientSlot is extracted from the success response. ```c // Generate random 4-byte client ID uint8_t clientId[4] = {0x12, 0x34, 0x56, 0x78}; uint8_t clientName[20] = "MyShowerApp\0"; // Build payload uint8_t payload[24]; memcpy(payload, clientId, 4); memcpy(payload + 4, clientName, 20); // Send Pair command (clientSlot = 0x00 for pairing) // After response, extract clientSlot from notification uint8_t clientSlot = notificationPayload[0]; // 1-15 ``` -------------------------------- ### Target Temperature Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Examples of target temperature values and their corresponding Celsius degrees. Temperature is encoded as Celsius * 10. ```text 0x00C8 (200) = 20.0°C 0x017C (380) = 38.0°C (typical default) 0x01C2 (450) = 45.0°C ``` -------------------------------- ### Maximum Flow Rate Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Examples of setting the maximum flow rate for an outlet. Devices typically support on/off flow (0x64) or off (0x00). ```text 0x64 (100%) 0x00 (0%) ``` -------------------------------- ### Unpair Command Example in C Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Shows how to construct the payload for the Unpair command using the clientSlot. This command is used to unregister a client application from the device. ```c // Unpair this client uint8_t payload[1] = {clientSlot}; // Send command with commandTypeId = 0xeb, payloadLength = 1 // Expect SuccessOrFailure notification ``` -------------------------------- ### Valid Pairing Name Example (C) Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/errors.md Demonstrates how to correctly format a client name for pairing, ensuring it is valid UTF-8 and exactly 20 bytes including null padding. ```c char clientName[20] = {0}; strncpy(clientName, "MyApp", 19); // 5 chars + 15 nulls = 20 bytes ``` -------------------------------- ### Duration Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Examples of duration values and their corresponding time in seconds. Duration is encoded as seconds / 10. ```text 0x00 (0) = No timeout (run until manually stopped) 0x0A (10) = 100 seconds 0x3C (60) = 600 seconds (10 minutes) 0x78 (120) = 1200 seconds (20 minutes) 0xC0 (192) = 1920 seconds (32 minutes max) ``` -------------------------------- ### Wireless Remote Button Outlet Enablement Examples Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md These examples show how to configure which outlets can be controlled by wireless remote buttons using a bitmask. Bit 0 controls Outlet 1, and Bit 1 controls Outlet 2. Constraints apply regarding device state and lockout periods. ```plaintext 0x00 = Both outlets disabled via remote (manual control only) 0x01 = Outlet 1 enabled, Outlet 2 disabled 0x02 = Outlet 1 disabled, Outlet 2 enabled 0x03 = Both outlets enabled (typical) ``` -------------------------------- ### Notification Buffering Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/SUMMARY.txt Demonstrates a conceptual approach to buffering incoming Bluetooth notifications, which is crucial for handling notifications that might arrive out of order or require reassembly. ```c // Example of notification buffering logic (conceptual) // Assumes a structure `NotificationPacket` and a buffer management system #define NOTIFICATION_BUFFER_SIZE 10 // Placeholder for notification data structure typedef struct { uint8_t type; uint8_t* payload; size_t payload_size; bool is_complete; } NotificationPacket; NotificationPacket notification_buffer[NOTIFICATION_BUFFER_SIZE]; size_t buffer_count = 0; void add_notification_to_buffer(const uint8_t* raw_data, size_t raw_data_size) { // Parse raw_data to identify notification type, sequence, and payload // If buffer is full, handle overflow (e.g., drop oldest, return error) if (buffer_count >= NOTIFICATION_BUFFER_SIZE) { // Handle buffer full scenario return; } // Create or update a NotificationPacket in the buffer // notification_buffer[buffer_count] = parsed_notification; // buffer_count++; // Logic to check if a complete notification can be assembled from buffered chunks // ... } void process_buffered_notifications() { // Iterate through the buffer, identify complete notifications, process them, and remove from buffer // ... } ``` -------------------------------- ### Start Preset Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Sends a command to activate a specified preset, initiating water flow with its configured settings. The payload contains only the preset slot number. ```c uint8_t payload[1] = {presetSlot}; // Send command, expect ControlsOperated notification ``` -------------------------------- ### Device Nickname Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/types.md Shows the in-memory representation of a device nickname, null-padded to 16 bytes. Supports UTF-8 encoding. ```text "Master Bath\0\0\0\0\0" 4D 61 73 74 65 72 20 42 61 74 68 00 00 00 00 00 ``` -------------------------------- ### Invalid Pairing Name Example (C) Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/errors.md Illustrates an invalid client name scenario where the string exceeds the 20-byte limit after null-padding, leading to rejection. ```c char clientName[20] = {0}; strncpy(clientName, "ThisIsAVeryLongApplicationName", 19); // Truncated to "ThisIsAVeryLongApplic" ``` -------------------------------- ### Preset Management Commands Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/SUMMARY.txt Details commands for managing preset slots and details, including updating, deleting, and starting presets. Each command has a specific hexadecimal code. ```text RequestPresetSlots (0x30) RequestPresetDetails (0x30) UpdatePresetDetails (0xb0) DeletePresetDetails (0xb0) StartPreset (0xb1) ``` -------------------------------- ### Error Indication Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/errors.md When any command fails to execute, the device responds with a SuccessOrFailure notification containing the error code 0x80. No additional details are provided. ```text Client sends: UpdatePresetDetails while water is running Device response: SuccessOrFailure with 0x80 Reason: Running state = 0x01 (RUNNING), not 0x00 (STOPPED) Fix: Stop outlets first, wait 5 seconds, then retry ``` -------------------------------- ### Parse Device Settings Response Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Example of parsing the response payload for the RequestDeviceSettings command. This payload contains configuration flags for wireless outlets, default presets, and controller settings. ```c // Parse DeviceSettings response (4 bytes) uint8_t wirelessEnabled = response[1]; uint8_t defaultPreset = response[2]; uint8_t controllerSettings = response[3]; ``` -------------------------------- ### CRC-16/IBM-3740 Implementation Example Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/INDEX.md This C code snippet demonstrates the implementation of the CRC-16/IBM-3740 algorithm, commonly used for data integrity checks in the device's communication protocol. Ensure correct initialization and data processing for accurate CRC calculation. ```c #include // CRC-16/IBM-3740 polynomial: 0x8005 // Initial value: 0x0000 // Final XOR: 0x0000 // Reflect input: false // Reflect output: false uint16_t calculate_crc16_ibm(const uint8_t* data, size_t length) { uint16_t crc = 0x0000; for (size_t i = 0; i < length; ++i) { crc ^= (uint16_t)data[i] << 8; for (int j = 0; j < 8; ++j) { if (crc & 0x8000) { crc = (crc << 1) ^ 0x1021; // 0x1021 is 0x8005 << 1 XOR 0x8005 } else { crc <<= 1; } } } return crc; } ``` -------------------------------- ### UpdatePresetDetails Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Creates or updates a preset configuration. Requires the system to be in a STOPPED state. ```APIDOC ## UpdatePresetDetails ### Description Create or update a preset configuration. ### Command ID 0xb0 ### Payload Length 24 bytes ### Restricted Yes (requires running state = STOPPED) ### Payload Structure ``` [ presetSlot, targetTemperature (2B), flowRate, durationSeconds, outletsEnabledBits, 0x00, 0x00, presetName (8B?) ] ``` #### Parameters | Field | Type | Size | Encoding | |---|---|---|---| | presetSlot | byte | 1 | Destination slot (0-15) | | targetTemperature | int16 | 2 | Big-endian, value = degrees × 10 | | flowRate | byte | 1 | 0x64 for normal flow | | durationSeconds | byte | 1 | Seconds = value × 10 (0 = no timeout) | | outletsEnabled | byte | 1 | Bitmask: bit 0=outlet1, bit 1=outlet2 | | reserved1 | byte | 1 | Must be 0x00 | | reserved2 | byte | 1 | Must be 0x00 | | presetName | UTF-8 | 8+ | Name, null-padded to total 24 bytes | ### Response Notification Type SuccessOrFailure ### Response Details - Success: Payload byte = 0x01 - Failure: Payload byte = 0x80 ### Example Usage ```c uint8_t payload[24] = {0}; payload[0] = 0; // slot 0 int16_t temp = 380; // 38.0°C payload[1] = (temp >> 8) & 0xFF; payload[2] = temp & 0xFF; payload[3] = 0x64; // full flow payload[4] = 10; // 100 seconds duration payload[5] = 0x03; // both outlets enabled payload[6] = 0x00; payload[7] = 0x00; strncpy((char*)payload + 8, "Morning Preset", 15); // Send command with commandTypeId = 0xb0 ``` ``` -------------------------------- ### Update Preset Details Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to create or update a preset. Requires `runningState = STOPPED` and is subject to a 5-second lockout after stopping. The response is a SuccessOrFailure notification. ```c // Create/update preset UpdatePresetDetails(0xb0, presetBytes24) → SuccessOrFailure notification ``` -------------------------------- ### Set Controller Settings Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to set controller-wide settings. Requires `runningState = STOPPED` and is subject to a 5-second lockout after stopping. The response is a SuccessOrFailure notification. ```c // Set controller settings UpdateControllerSettings(0xbe, [0x03, settingsBits]) → SuccessOrFailure notification ``` -------------------------------- ### Parse Device State Response Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Example of parsing the response payload for the RequestDeviceState command. This payload contains the current operational state, temperatures, and flow rates. ```c // Parse DeviceState response (10 bytes) uint8_t runningState = response[0]; int16_t targetTemp = (response[1] << 8) | response[2]; int16_t actualTemp = (response[3] << 8) | response[4]; uint8_t outlet1Flow = response[5]; uint8_t outlet2Flow = response[6]; ``` -------------------------------- ### Update Controller Settings Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to configure controller settings such as swapping the top button's outlet assignment and disabling standby lighting. The `controllerSettingBits` parameter is a bitmask. Constraints apply regarding device state and lockout periods. ```protobuf UpdateControllerSettings(controllerSettingBits: uint8) ``` -------------------------------- ### Pair Mira Shower Controller (First Connection) Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/implementation-guide.md Steps to pair a new client with the shower controller. This involves generating a client ID, preparing a client name, building a pair command, and listening for a success notification. The CRC calculation for the pair command requires a special pairing-specific identifier. ```c // Step 1: Generate random client ID uint8_t clientId[4]; random_bytes(clientId, 4); // Step 2: Prepare client name (UTF-8, null-padded to 20 bytes) uint8_t clientName[20] = {0}; strncpy((char*)clientName, "MyShowerApp", 19); // Step 3: Build Pair command uint8_t payload[24]; memcpy(payload, clientId, 4); memcpy(payload + 4, clientName, 20); // Step 4: Send command // clientSlot = 0x00 (special for pairing) // commandTypeId = 0xeb // payloadLength = 24 // payload = 24 bytes above // crc = CRC-16/IBM-3740 over [0x00, 0xeb, 24, payload, pairingSpecificId] // Note: pairingSpecificId is NOT the clientId, must be discovered // Step 5: Listen for SuccessOrFailure notification // If successful, first payload byte is allocated clientSlot uint8_t assignedClientSlot = notification_payload[0]; // Step 6: Store assignedClientSlot and clientId for future connections save_to_persistent_storage(assignedClientSlot, clientId); ``` -------------------------------- ### RequestPresetDetails Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Queries the configuration for a specific preset slot. Returns a 24-byte payload with preset details. ```APIDOC ## RequestPresetDetails ### Description Query configuration for a specific preset. ### Command ID 0x30 ### Payload Structure ``` [ 0x40 + presetSlot ] ``` #### Parameters | Field | Type | Size | Description | |---|---|---|---| | slot indicator | byte | 1 | 0x40 + presetSlot (e.g., 0x40 for slot 0, 0x41 for slot 1) | ### Response Notification Type PresetDetails ### Response Details 24-byte payload containing preset configuration. #### Payload Structure ``` [ presetSlot, targetTemperature (2B), TBC, durationSeconds, outletsEnabledBits, TBC, TBC, presetName (8B?) ] ``` | Field | Type | Size | Encoding | |---|---|---|---| | presetSlot | byte | 1 | Slot number (0-15) | | targetTemperature | int16 | 2 | Big-endian, degrees = value / 10 | | reserved1 | byte | 1 | Purpose not documented | | durationSeconds | byte | 1 | Seconds = value × 10 | | outletsEnabled | byte | 1 | Bitmask: bit 0=outlet1, bit 1=outlet2 | | reserved2 | byte | 1 | Purpose not documented | | reserved3 | byte | 1 | Purpose not documented | | presetName | UTF-8 | 8+ | Preset name, null-padded to total 24 bytes | ### Example Usage ```c // Parse PresetDetails response (24 bytes) uint8_t slot = response[0]; int16_t targetTemp = (response[1] << 8) | response[2]; uint8_t duration = response[4]; uint8_t outlets = response[5]; char presetName[16]; memcpy(presetName, response + 8, 16); ``` ``` -------------------------------- ### Connect to BLE Device Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/implementation-guide.md Establishes a BLE connection, subscribes to notifications, and verifies the connection with a handshake. Requires `ble_connect()`, `subscribe_notifications()`, and `request_device_state()` to be implemented. Initializes connection-related global variables. ```c int connect_device(void) { // Connect BLE if (ble_connect(device_address) < 0) { return -1; } // Set up notifications if (subscribe_notifications() < 0) { return -1; } // Verify connection DeviceState state; if (request_device_state(&state) < 0) { return -1; // Handshake failed } clientConnection.connected = 1; clientConnection.lastActivity = time(NULL); clientConnection.connectionTime = time(NULL); return 0; } ``` -------------------------------- ### Set Default Preset Slot Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to set the default preset slot. Requires `runningState = STOPPED` and is subject to a 5-second lockout after stopping. The response is a SuccessOrFailure notification. ```c // Set default preset UpdateDefaultPresetSlot(0xbe, [0x02, presetSlot]) → SuccessOrFailure notification ``` -------------------------------- ### Query Client Details Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Retrieve the application name for a specific client slot. The response is a null-padded UTF-8 string. Remember to track which slot was queried to correlate with the response. ```c uint8_t payload[1] = {0x10 + clientSlot}; // Send command, expect ClientDetails notification with 20 bytes // Payload is null-padded UTF-8 client name ``` -------------------------------- ### Read Preset List Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to retrieve the available preset slots. The response is a 2-byte notification containing a bitmask. ```c // Get preset list RequestPresetSlots(0x30) → Slots notification (2 bytes) with bitmask ``` -------------------------------- ### RequestDeviceSettings Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/README.md Requests the current settings of the device. This command has no payload. ```plaintext RequestDeviceSettings 0x3e 0 No payload ``` -------------------------------- ### CRC Verification Steps Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/errors.md Provides guidance on verifying CRC calculations for commands, including the data payload and expected CRC algorithm. ```text CRC calculated over: [clientSlot, commandTypeId, payloadLength, payload, clientId] Two final bytes in command are CRC in big-endian format ``` -------------------------------- ### Project Document Relationships Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/MANIFEST.md Illustrates the hierarchical and relational structure of the project's documentation files, showing how different sections link together. ```text INDEX.md (navigation hub) ├→ README.md (overview) └→ protocol-overview.md (fundamentals) ├→ commands.md (requests) ├→ notifications.md (responses) └→ types.md (data definitions) ├→ configuration.md (settings) └→ errors.md (error handling) └→ implementation-guide.md (practical patterns) ``` -------------------------------- ### Read Device Settings Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to retrieve all current device settings. The response includes a 4-byte DeviceSettings notification. ```c // Get all device settings RequestDeviceSettings(0x3e) → DeviceSettings notification (4 bytes) ``` -------------------------------- ### Device State Machine Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/README.md Illustrates the possible states of the device (STOPPED, RUNNING, PAUSED) and the transitions between them, including special states like COLD/MINIMUM. ```text STOPPED (0x00) ↓ activate via StartPreset or OperateOutlets(0x01) RUNNING (0x01) ↓ preset expires or manual stop PAUSED (0x03) ↓ 5 minutes timeout or manual stop STOPPED (0x00) Special: COLD/MINIMUM (0x05) - manual controls only ``` -------------------------------- ### Query Client Slots Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Use this command to determine which client slots are currently in use on the device. The response is a bitmask indicating occupied slots. ```c uint8_t payload[1] = {0x00}; // Send command, expect Slots notification with 2 bytes // Bit 0 = slot 0 occupied, bit 1 = slot 1 occupied, etc. uint16_t slotMask = (response[0]) | (response[1] << 8); ``` -------------------------------- ### Preset Management Functions Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/implementation-guide.md Provides C functions for creating and activating presets on the device. Ensure the device is stopped before creating a preset and verify the preset slot exists before activation. ```c typedef struct { uint8_t slot; char name[16]; int16_t targetTemp; uint8_t duration; // 0 = no limit uint8_t outletsEnabled; // Bitmask } PresetConfig; int create_preset(PresetConfig* config) { // Verify device is stopped DeviceState state; request_device_state(&state); if (state.runningState != 0x00) { printf("Error: Device must be stopped to create preset\n"); return -1; } // Build UpdatePresetDetails command uint8_t payload[24] = {0}; payload[0] = config->slot; payload[1] = (config->targetTemp >> 8) & 0xFF; payload[2] = config->targetTemp & 0xFF; payload[3] = 0x64; // Flow rate payload[4] = config->duration; payload[5] = config->outletsEnabled; payload[6] = 0x00; payload[7] = 0x00; strncpy((char*)(payload + 8), config->name, 15); // Send command and handle response return send_command_with_retry(payload, 24); } int activate_preset(uint8_t preset_slot) { // Check preset exists uint16_t presetMask; request_preset_slots(&presetMask); if (!(presetMask & (1 << preset_slot))) { printf("Error: Preset slot %d does not exist\n", preset_slot); return -1; } // Build StartPreset command uint8_t command[6]; command[0] = clientSlot; command[1] = 0xb1; // StartPreset command[2] = 0x01; // Payload length command[3] = preset_slot; // Add CRC... return send_command_with_retry(command, 6); } ``` -------------------------------- ### Update Outlet Settings Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to update the settings for a specific outlet. Requires `runningState = STOPPED` and is subject to a 5-second lockout after stopping. The response is a SuccessOrFailure notification. Specify the outlet number (1 or 2) as the argument. ```c // Update outlet settings UpdateOutletSettings(0x8f, settingsBytes11) // Outlet 1 UpdateOutletSettings(0x90, settingsBytes11) // Outlet 2 → SuccessOrFailure notification ``` -------------------------------- ### Read Preset Details Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to retrieve the details of a specific preset. The response is a 24-byte PresetDetails notification. ```c // Get preset details RequestPresetDetails(0x30) → PresetDetails notification (24 bytes) ``` -------------------------------- ### Device Management Commands Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/SUMMARY.txt Commands for managing the device, such as restarting, factory resetting, and handling unknown technical information requests. Each command has a specific hexadecimal code. ```text RestartDevice (0xf4) FactoryResetDevice (0xf4) UnknownRequestTechnicalInformation (0x41) ``` -------------------------------- ### Update Preset Details Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Constructs a 24-byte payload to create or update a preset configuration. Sets slot, temperature, flow rate, duration, enabled outlets, and preset name. ```c uint8_t payload[24] = {0}; payload[0] = 0; // slot 0 int16_t temp = 380; // 38.0°C payload[1] = (temp >> 8) & 0xFF; payload[2] = temp & 0xFF; payload[3] = 0x64; // full flow payload[4] = 10; // 100 seconds duration payload[5] = 0x03; // both outlets enabled payload[6] = 0x00; payload[7] = 0x00; strncpy((char*)payload + 8, "Morning Preset", 15); // Send command with commandTypeId = 0xb0 ``` -------------------------------- ### Request Outlet Settings Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Query detailed configuration for a specific outlet using command IDs 0x0f for Outlet 1 or 0x10 for Outlet 2. The response payload contains outlet configuration details. ```c // For outlet 1, use commandTypeId = 0x0f // For outlet 2, use commandTypeId = 0x10 // Parse OutletSettings response (11 bytes) uint8_t outletFlag = response[0]; uint8_t maxFlow = response[3]; ``` -------------------------------- ### Running State vs. Outlet State Consistency Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/errors.md Illustrates valid and invalid configurations for the runningState and outlet flow rates. The device enforces consistency between these states. ```text Invalid: runningState=0x00, outlet1FlowRate=0x64, outlet2FlowRate=0x00 Valid: runningState=0x00, outlet1FlowRate=0x00, outlet2FlowRate=0x00 Invalid: runningState=0x01, outlet1FlowRate=0x00, outlet2FlowRate=0x00 Valid: runningState=0x01, outlet1FlowRate=0x64, outlet2FlowRate=0x00 (or both 0x64) ``` -------------------------------- ### Shower Client Reference Implementation Structure Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/implementation-guide.md This C structure defines the essential components for a shower controller client, including connection details, registration information, device status, and notification handling mechanisms. It serves as a blueprint for building a complete client application. ```c struct ShowerClient { // Connection state struct { char address[18]; int socket; int connected; } ble; // Client registration struct { uint8_t clientSlot; uint8_t clientId[4]; char clientName[20]; } client; // Device state struct { uint8_t runningState; int16_t targetTemp; int16_t actualTemp; uint8_t outlet1; uint8_t outlet2; int16_t secondsRemaining; } state; // Notification handling struct { uint8_t buffer[256]; int bufferLen; uint8_t currentClientSlot; } notifications; // Configuration cache struct { int16_t outlet1MinTemp; int16_t outlet1MaxTemp; char deviceNickname[16]; uint8_t presetMask[2]; } cache; }; ``` -------------------------------- ### Request Preset Slots Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Sends a command to query which preset slots are occupied. The response is a 2-byte bitmask indicating the presence of presets. ```c uint8_t payload[1] = {0x80}; // Send command, expect Slots notification with 2 bytes uint16_t presetMask = (response[0]) | (response[1] << 8); ``` -------------------------------- ### Update Outlet Settings Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Configure detailed settings for a specific outlet. This command requires the running state to be STOPPED. Ensure temperature constraints are met. ```c uint8_t payload[11]; payload[0] = 0x00; // outlet 1 flag payload[1] = 0x00; // outlet 1 flag payload[2] = 0x08; payload[3] = 0x64; // 100% max flow payload[4] = 12; // 120 seconds max duration int16_t maxTemp = 450; // 45.0°C payload[5] = (maxTemp >> 8) & 0xFF; payload[6] = maxTemp & 0xFF; int16_t minTemp = 200; // 20.0°C payload[7] = (minTemp >> 8) & 0xFF; payload[8] = minTemp & 0xFF; int16_t limit = 380; // 38.0°C payload[9] = (limit >> 8) & 0xFF; payload[10] = limit & 0xFF; // Send command with commandTypeId = 0x8f (outlet 1) or 0x90 (outlet 2) ``` -------------------------------- ### Preset Configuration Structure Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/types.md Payload structure for creating or updating presets via the UpdatePresetDetails command. ```c struct PresetConfiguration { uint8_t presetSlot; int16_t targetTemperature; uint8_t flowRate; uint8_t durationSeconds; uint8_t outletsEnabledBits; uint8_t reserved1; uint8_t reserved2; char presetName[16]; }; ``` -------------------------------- ### Device Query Commands Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/SUMMARY.txt Lists various commands to query device state, settings, and details. Each command has a specific hexadecimal code. ```text RequestDeviceState (0x07) RequestDeviceSettings (0x3e) RequestNickname (0x44) RequestClientSlots (0x6b) RequestClientDetails (0x6b) RequestOutletSettings (0x0f, 0x10) RequestTechnicalInformation (0x32) ``` -------------------------------- ### Handle Unknown Technical Information Request Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md This command is used for an undocumented technical information request. It expects a 4-byte response, but its purpose is not fully documented. ```c // No payload // Send command, expect 4-byte response ``` -------------------------------- ### Update Default Preset Slot Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to set the default preset slot that activates on device power-up. Set to 0 to disable auto-activation. Constraints apply regarding device state and lockout periods. ```protobuf UpdateDefaultPresetSlot(presetSlot: uint8) ``` -------------------------------- ### Read Outlet Settings Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to retrieve the settings for a specific outlet. The response is an 11-byte OutletSettings notification. Specify the outlet number (1 or 2) as the argument. ```c // Get outlet settings RequestOutletSettings(0x0f) // Outlet 1 RequestOutletSettings(0x10) // Outlet 2 → OutletSettings notification (11 bytes) ``` -------------------------------- ### Restart Device Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Restarts the device without losing configuration. This command requires the device to be in a STOPPED state and has a 1-byte payload. ```c uint8_t payload[1] = {0x01}; // Send command with commandTypeId = 0xf4 ``` -------------------------------- ### RequestTechnicalInformation Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Queries the device for technical component versions. The response includes detailed information about the software and types of various components like the valve, UI, and Bluetooth module. ```APIDOC ## RequestTechnicalInformation ### Description Query technical component versions in the device. The response provides 16-byte payload containing component version information. ### Command ID 0x32 ### Payload Structure ``` [ 0x01 ] ``` ### Response Notification Type TechnicalInformation ### Response Details 16-byte payload containing component version information. **Payload Structure**: ``` [ valveType (2B), valveSoftwareVersion (2B), uiType (2B), uiSoftwareVersion (2B), ui2Type (2B), ui2SoftwareVersion (2B), bluetoothType (2B), bluetoothSoftwareVersion (2B) ] ``` | Field | Type | Size | Notes | |---|---|---|---| | valveType | int16 | 2 | Component type identifier (first byte typically 0x00) | | valveSoftwareVersion | int16 | 2 | Software version | | uiType | int16 | 2 | Main controller UI type (42=Dual Shower, 44=Shower+Bath, others TBD) | | uiSoftwareVersion | int16 | 2 | UI software version | | ui2Type | int16 | 2 | Wired remote button type (or second UI) | | ui2SoftwareVersion | int16 | 2 | Wired remote software version | | bluetoothType | int16 | 2 | Bluetooth module type | | bluetoothSoftwareVersion | int16 | 2 | Bluetooth firmware version | ### Notes - All fields assumed 2 bytes, though first byte frequently 0x00 - Device model type is indicated in uiType field ### Example Usage ```c uint8_t payload[1] = {0x01}; // Send command, expect TechnicalInformation notification (16 bytes) uint16_t uiType = (response[4] << 8) | response[5]; ``` ``` -------------------------------- ### RequestOutletSettings Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/README.md Requests the settings for a specific outlet. The command ID may vary depending on the outlet. ```plaintext RequestOutletSettings 0x0f or 0x10 depending on outlet 0 No payload ``` -------------------------------- ### Standard BLE Operation Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/README.md Steps for subsequent BLE connections, including connecting to a known device, subscribing to notifications, sending commands with stored client information, and handling responses. ```text 1. BLE Connect → Open connection to known device 2. Subscribe → Enable notifications 3. Send Commands → Use stored clientSlot + clientId → All commands include clientSlot in first byte → All CRCs calculated with stored clientId 4. Handle Responses → Reassemble chunked notifications, parse results ``` -------------------------------- ### Request Technical Information Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Query technical component versions from the device. The response contains detailed information about various component types and their software versions. ```c uint8_t payload[1] = {0x01}; // Send command, expect TechnicalInformation notification (16 bytes) uint16_t uiType = (response[4] << 8) | response[5]; ``` -------------------------------- ### RequestDeviceState Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/README.md Requests the current state of the device. This command has no payload. ```plaintext RequestDeviceState 0x07 0 No payload ``` -------------------------------- ### Delete Preset Details Command Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Prepares a 24-byte payload to delete a specific preset configuration. Requires the preset slot number and a deletion marker. ```c uint8_t payload[24] = {0}; payload[0] = presetSlot; payload[1] = 0x01; // deletion marker // Send command with commandTypeId = 0xb0 ``` -------------------------------- ### Temperature Conversion Functions Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/implementation-guide.md Provides C functions for converting Celsius to a protocol integer format and vice-versa. Includes validation for temperature ranges and outlet settings. ```c #include // Convert Celsius to protocol value (int16) int16_t celsius_to_protocol(double celsius) { // Clamp to reasonable range if (celsius < 5.0) celsius = 5.0; if (celsius > 50.0) celsius = 50.0; return (int16_t)round(celsius * 10.0); } // Convert protocol value to Celsius double protocol_to_celsius(int16_t value) { return value / 10.0; } // Validate temperature constraints int validate_outlet_temps(int16_t min, int16_t limit, int16_t max) { double minC = protocol_to_celsius(min); double limitC = protocol_to_celsius(limit); double maxC = protocol_to_celsius(max); if (minC > limitC) return 0; // Invalid if (maxC < limitC) return 0; // Invalid return 1; // Valid } // Example: Set outlet to safe temperature range int set_outlet_safe_temps(uint8_t outlet_num) { int16_t minTemp = celsius_to_protocol(20.0); int16_t maxTemp = celsius_to_protocol(45.0); int16_t limitTemp = celsius_to_protocol(38.0); if (!validate_outlet_temps(minTemp, limitTemp, maxTemp)) { printf("Invalid temperature configuration\n"); return -1; } // Send UpdateOutletSettings command... return 0; } ``` -------------------------------- ### RestartDevice Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Restarts the device without losing its configuration. This command requires the device to be in a stopped state. ```APIDOC ## RestartDevice ### Description Restart the device without losing configuration. Requires running state = STOPPED. ### Command ID 0xf4 ### Payload Structure ``` [ 0x01 ] ``` ### Response Notification Type SuccessOrFailure ### Response Details - Success: Payload byte = 0x01 - Failure: Payload byte = 0x80 ### Example Usage ```c uint8_t payload[1] = {0x01}; // Send command with commandTypeId = 0xf4 ``` ``` -------------------------------- ### DeletePresetDetails Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/commands.md Deletes a preset configuration. Requires the system to be in a STOPPED state. ```APIDOC ## DeletePresetDetails ### Description Delete a preset configuration. ### Command ID 0xb0 ### Payload Length 24 bytes ### Restricted Yes (requires running state = STOPPED) ### Payload Structure ``` [ presetSlot, 0x01, 0x00 (repeated 22 times) ] ``` #### Parameters | Field | Type | Size | Description | |---|---|---|---| | presetSlot | byte | 1 | Preset slot to delete (0-15) | | deletion marker | byte | 1 | Must be 0x01 | | padding | bytes | 22 | All zero bytes (0x00) | ### Response Notification Type SuccessOrFailure ### Response Details - Success: Payload byte = 0x01 - Failure: Payload byte = 0x80 ### Example Usage ```c uint8_t payload[24] = {0}; payload[0] = presetSlot; payload[1] = 0x01; // deletion marker // Send command with commandTypeId = 0xb0 ``` ``` -------------------------------- ### Set Wireless Remote Outlets Source: https://github.com/nhannam/shower-controller-documentation/blob/main/_autodocs/configuration.md Use this command to configure which outlets are enabled for wireless remote control. Requires `runningState = STOPPED` and is subject to a 5-second lockout after stopping. The response is a SuccessOrFailure notification. ```c // Set wireless remote outlets UpdateWirelessRemoteButtonSettings(0xbe, [0x01, outletsEnabled]) → SuccessOrFailure notification ```