-
Notifications
You must be signed in to change notification settings - Fork 9
Remote API
Howl provides a remote API that can be used to trigger certain functions of the app. This includes changing controls on the main control panel (such as raising the power level on a channel, or toggling mute) and controlling some functions of the player (such as loading a file, or starting and stopping playback).
The API is useful to advanced users and developers who would like to automate certain functions. For example controlling Howl with their own custom scripts, or using Home Assistant to tie functionality to smart home devices such as physical buttons.
Howl's remote API is disabled by default. Enabling the "Allow remote access" option in Howl's "Settings" tab will allow connections to the API.
Howl uses a "REST style" API where various endpoints can be accessed via HTTP requests to trigger functions. JSON formatting is generally used to provide parameters and to return information. The API uses a simplified design that does not fully adhere to REST principles (e.g. all requests use HTTP POST).
Access to Howl's API is controlled by the "Remote access key" displayed in Howl's "Settings" tab. This must be submitted as a bearer token in the Authorization header in all requests to the API e.g. Authorization: Bearer YOUR_ACCESS_KEY
It's expected that the API will be used for communication between devices on a secure home network. Use on unsecured public networks or over the internet is not recommended, since the access key is sent in plain text, and could easily be obtained by an attacker.
Howl's API is accessed through the local network IP address of the device running Howl (typically your Android phone). The API always uses HTTP port 4695. For example to make a request to the /status endpoint, you would send an HTTP POST request to http://[YOUR_DEVICE_IP]:4695/status
A full Python implementation of the Howl API that includes all the endpoints ("howlapi.py") can be found in the "python" folder of the repository. This should be ready for developers to use.
A basic demo of web-based remote control for Howl ("howl_remote.html") can be found in the "remote_control" folder of the repository. It allows users to control an instance of Howl that is running on the same network. It's not particularly polished, being largely AI generated, and is just intended to showcase the sort of thing that could be made using the API.
Howl responds to all successful API requests with an HTTP 200 OK status code. Unless otherwise noted below, the response body will contain a JSON object representing the current state of the application. This allows you to immediately verify the result of your command (e.g. seeing the new power level after a set_power request).
Howl's standard JSON status response contains a root object with two nested objects: options (representing the main control panel state) and player (representing the player state).
Example success response body:
{
"options": {
"power_a": 30,
"power_b": 36,
"power_a_limit": 70,
"power_b_limit": 70,
"mute": false,
"auto_increase_power": false,
"swap_channels": false,
"freq_range_min": 0.0,
"freq_range_max": 0.5
},
"player": {
"playing": true,
"position": 30.5,
"title": "nice_pattern.hwl",
"duration": 120.0
}
}Response fields:
-
options-
power_a(Int): Current power level for Channel A (0-200). -
power_b(Int): Current power level for Channel B (0-200). -
power_a_limit(Int): The configured power limit for Channel A. -
power_b_limit(Int): The configured power limit for Channel B. -
mute(Boolean): True when global mute is active. -
auto_increase_power(Boolean): True when power auto increase is active. -
swap_channels(Boolean): True when swap channels is active. -
freq_range_min(Float): Position of the minimum frequency range slider (0.0 to 1.0). -
freq_range_max(Float): Position of the maximum frequency range slider (0.0 to 1.0).
-
-
player-
playing(Boolean): True when any content is actively playing. -
position(Float): The current playback position in seconds. -
title(String): The title or filename of the playback source. -
duration(Float): Total duration of the current playback source in seconds.
-
If a request fails, Howl responds with an appropriate 4xx or 5xx HTTP status code.
-
401 Unauthorized: Returned if the
Authorizationheader is missing or the access key is incorrect. - 400 Bad Request: Returned if the request parameters are invalid (e.g. missing required fields, invalid file format).
- 500 Internal Server Error: Returned if an unexpected error occurs on the server while processing the request.
Error responses generated by Howl are returned in JSON format. The response body contains a root object with a nested error object, which includes a message string describing the specific error. Please note that certain errors generated by libraries we use (such as authentication failures) may return error messages in plain text instead of our standard JSON format.
Example error response body:
{
"error": {
"message": "Invalid funscript file"
}
}Response fields:
-
error-
message(String): A description of the error that occurred.
-
Retrieves the current status of the application without modifying any state.
Parameters: None.
Example request body:
{}Sets the absolute power level for one or both channels.
Parameters:
-
power_a(Int, Optional): The desired power level for channel A (0-200). -
power_b(Int, Optional): The desired power level for channel B (0-200).
Example request body:
{
"power_a": 20,
"power_b": 35
}Increases the power level on one or both channels by a specified amount.
Parameters:
-
channel(Int, Required): The channel identifier (0 for Channel A, 1 for Channel B, -1 for both channels). -
step(Int, Optional): The amount to increase the power by. Set to 0 to use the step size configured in Howl's settings (default 0).
Example request body:
{
"channel": 0,
"step": 5
}Decreases the power level on one or both channels by a specified amount.
Parameters:
-
channel(Int, Required): The channel identifier (0 for Channel A, 1 for Channel B, -1 for both channels). -
step(Int, Optional): The amount to decrease the power by. Set to 0 to use the step size configured in Howl's settings (default 0).
Example request body:
{
"channel": 1,
"step": 5
}Sets or toggles the global mute state.
Parameters:
-
value(Boolean, Optional): The desired mute state (trueto mute,falseto unmute). If the value parameter is omitted, the current mute state will be toggled.
Example request body (Set mute on):
{
"value": true
}Example request body (Toggle mute):
{}Sets or toggles the swap channels feature.
Parameters:
-
value(Boolean, Optional): The desired state (trueto enable swap channels,falseto disable). If the value parameter is omitted, the current state will be toggled.
Example request body:
{
"value": true
}Sets or toggles the auto increase power feature.
Parameters:
-
value(Boolean, Optional): The desired state (trueto enable auto increase,falseto disable). If the value parameter is omitted, the current state will be toggled.
Example request body:
{
"value": false
}Adjusts Howl's main frequency range bar control, changing the frequency range that will be used during playback. Setting min to 0.0 and max to 1.0 will use the maximum range offered by the current output.
Parameters:
-
min(Float, Required): Position of the minimum frequency slider (0.0 to 1.0). -
max(Float, Required): Position of the maximum frequency slider (0.0 to 1.0).
Constraints:
-
maxmust be greater thanmin. - The difference between
maxandminmust be at least 0.01.
Example request body:
{
"min": 0.25,
"max": 0.75
}Starts or resumes playback of the current source.
Parameters:
-
from(Float, Optional): The timestamp (in seconds) to start playback from. Only applicable to finite sources, such as HWL files and funscripts. If omitted, playback starts from the current position.
Example request body:
{
"from": 10.5
}Stops or pauses playback (can be resumed later with start_player).
Parameters: None.
Example request body:
{}Seeks to a specific timestamp in the current playback source. If the player is already playing, playback continues from the new position. Only finite sources (such as HWL files and funscripts) are seekable.
Parameters:
-
position(Float, Required): The timestamp (in seconds) to seek to.
Example request body:
{
"position": 45.0
}Retrieves a list of all available built-in activities. This is useful for discovering valid activity names to use with the /load_activity endpoint.
Parameters: None.
Response: Returns a JSON object with an activities array containing the internal name and display name of each available activity. Does not return our standard status response.
Example response body:
{
"activities": [
{
"name": "CALIBRATION1",
"display_name": "Calibration 1"
},
{
"name": "CALIBRATION2",
"display_name": "Calibration 2"
},
{
"name": "CHAOS",
"display_name": "Chaos"
},
{
"name": "FASTSLOW",
"display_name": "Fast/slow"
},
...
]
}Response fields:
-
activities(Array): A list of available activities.-
name(String): The internal identifier for the activity. -
display_name(String): A human-readable display name for the activity.
-
Example request body:
{}Loads one of Howl's built-in activities. Use the /available_activities endpoint to retrieve a list of valid activity names.
Parameters:
-
name(String, Required): The internal name of the activity to load (e.g."CALIBRATION1"or"CHAOS"). -
play(Boolean, Optional): The initial playback state, true to start playback immediately (default false).
Example request body:
{
"name": "RELENTLESS",
"play": false
}Loads a funscript (supplied as a string).
Parameters:
-
title(String, Optional): The name of the funscript, to display on the player. -
loop(Boolean, Optional): Automatically loop when we reach the end (default false). -
play(Boolean, Optional): The initial playback state, true to start playback immediately (default false). -
funscript(String, Required): The complete JSON content of the Funscript file as a string.
Example request body:
{
"title": "Very nice funscript",
"loop": false,
"play": true,
"funscript": "{ \"actions\":[{\"at\":0,\"pos\":0},{\"at\":3200,\"pos\":100},{\"at\":3920,\"pos\":60}, ... ]}"
}Loads a binary HWL file (supplied as a Base64 encoded string).
Parameters:
-
title(String, Optional): The name of the HWL file, to display on the player. -
loop(Boolean, Optional): Automatically loop when we reach the end (default true). -
play(Boolean, Optional): The initial playback state, true to start playback immediately (default false). -
hwl(String, Required): The binary content of the HWL file, encoded as a Base64 string.
Example request body:
{
"title": "greatpattern.hwl",
"loop": true,
"play": true,
"hwl": "SG93bCBmaWxlIGJpbmFyeSBkYXRhIGhlcmU ... "
}It's possible to set up any of Howl's API functions as actions in Home Assistant. This opens up many interesting possibilities, since they can then be tied to any of the thousands of smart home devices that Home Assistant supports, including sensors, physical buttons etc. Setting up a Home Assistant server is beyond the scope of this document, so we'll only cover what's necessary to integrate Howl.
The best method to add Howl actions is using Home Assistant's RESTful Command integration. This requires adding text to Home Assistant's configuration.yaml file to define each Howl API command you want to use, along with the parameters you want to send.
A simple example is provided below, which adds a "howl_inc_power" action to increase the power level on both channels by 1, and a corresponding "howl_dec_power" action to decrease the power level on both channels by 1.
You would replace "192.168.0.69" with the IP address of your device running Howl, and replace "ABCDEF123456" with your Howl API key.
# existing lines from your configuration.yaml file
rest_command:
howl_inc_power:
url: "http://192.168.0.69:4695/increment_power"
method: post
content_type: "application/json"
verify_ssl: false
headers:
Authorization: Bearer ABCDEF123456
payload: '{"channel": -1, "step": 1}'
howl_dec_power:
url: "http://192.168.0.69:4695/decrement_power"
method: post
content_type: "application/json"
verify_ssl: false
headers:
Authorization: Bearer ABCDEF123456
payload: '{"channel": -1, "step": 1}'It's necessary to restart Home Assistant after editing the file. Be very careful with spacing, as if any lines are aligned wrong, it will break.
Once the Howl actions are set up, you will be able to use them when creating automations in the Home Assistant web UI. You should find them listed under "Other actions / RESTful Command" when selecting the action for your automation.