Last active
August 1, 2026 05:34
-
-
Save sean6541/2193139c345e19905f9a2172ce6fcf1d to your computer and use it in GitHub Desktop.
Upload data from Home Assistant to the CWOP.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| blueprint: | |
| name: 'CWOP Upload' | |
| description: > | |
| Upload data from Home Assistant to the CWOP. | |
| Config: | |
| The sensor_* variables are the sensors whos data will be uploaded. | |
| The trigger_entities variable specifies the entries to trigger state changes on (this could be a list). | |
| The script "/config/blueprints/automation/sean6541/send_tcp.sh" must be executable and contain the following: | |
| #!/bin/bash | |
| printf "$3" | nc "$1" "$2" | |
| The send_tcp service must exist in Home Assistant. | |
| This can be configured with the following YAML: | |
| shell_command: | |
| send_tcp: '/config/blueprints/automation/sean6541/send_tcp.sh {{ host }} {{ port }} "{{ packet }}"' | |
| domain: automation | |
| input: | |
| send_tcp_service: | |
| name: 'Send TCP Service' | |
| description: 'The send_tcp service to execute.' | |
| selector: | |
| text: | |
| default: 'shell_command.send_tcp' | |
| host: | |
| name: 'APRS Internet Service (APRS-IS) Host' | |
| selector: | |
| text: | |
| default: 'cwop.aprs.net' | |
| port: | |
| name: 'Port (DONT CHANGE THIS)' | |
| selector: | |
| text: | |
| default: '14580' | |
| callsign: | |
| name: 'CWOP Callsign' | |
| selector: | |
| text: | |
| default: '' | |
| station: | |
| name: 'Station Type' | |
| description: '2–4 character code for the type of weather station unit.' | |
| selector: | |
| text: | |
| default: '' | |
| lat: | |
| name: 'Station Latitude (APRS-Compliant Format)' | |
| selector: | |
| text: | |
| default: '' | |
| lon: | |
| name: 'Station Longitude (APRS-Compliant Format)' | |
| selector: | |
| text: | |
| default: '' | |
| trigger_entities: | |
| name: 'Trigger Entities' | |
| selector: | |
| entity: | |
| default: '' | |
| delay: | |
| name: 'Delay After Uploading' | |
| selector: | |
| number: | |
| min: 0 | |
| max: 300 | |
| step: 1 | |
| unit_of_measurement: seconds | |
| mode: slider | |
| default: 10 | |
| sensor_winddir: | |
| name: 'Wind Direction Sensor' | |
| description: 'Must report direction in degrees.' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_windspeed: | |
| name: 'Wind Speed Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_windgust: | |
| name: 'Wind Gust Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_temp: | |
| name: 'Temperature Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_hrrain: | |
| name: 'Rainfall Last Hour Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_twentyfourhrrain: | |
| name: 'Rainfall Last 24 Hours Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_dayrain: | |
| name: 'Rainfall Since Midnight Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_humidity: | |
| name: 'Humidity Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_pressure: | |
| name: 'Barometric Pressure Sensor' | |
| selector: | |
| entity: | |
| default: '' | |
| sensor_luminosity: | |
| name: 'Luminosity Sensor (W/m2)' | |
| selector: | |
| entity: | |
| default: '' | |
| mode: single | |
| max_exceeded: silent | |
| trigger: | |
| - platform: state | |
| entity_id: !input trigger_entities | |
| variables: | |
| host: !input host | |
| port: !input port | |
| callsign: !input callsign | |
| station: !input station | |
| lat: !input lat | |
| lon: !input lon | |
| delay: !input delay | |
| sensor_winddir: !input sensor_winddir | |
| sensor_windspeed: !input sensor_windspeed | |
| sensor_windgust: !input sensor_windgust | |
| sensor_temp: !input sensor_temp | |
| sensor_hrrain: !input sensor_hrrain | |
| sensor_twentyfourhrrain: !input sensor_twentyfourhrrain | |
| sensor_dayrain: !input sensor_dayrain | |
| sensor_humidity: !input sensor_humidity | |
| sensor_pressure: !input sensor_pressure | |
| sensor_luminosity: !input sensor_luminosity | |
| time: > | |
| {% set utc_time = utcnow() %} | |
| {{ '%02d' | format(utc_time.hour | int) }}{{ '%02d' | format(utc_time.minute | int) }}{{ '%02d' | format(utc_time.second | int) }} | |
| winddir: > | |
| {% if sensor_winddir == '' %} | |
| _... | |
| {% else %} | |
| {% set value = states(sensor_winddir) %} | |
| _{{ | |
| '...' if value in ('unavailable', 'unknown') | |
| else '%03d' | format(value | float | round | int) | |
| }} | |
| {% endif %} | |
| windspeed: > | |
| {% if sensor_windspeed == '' %} | |
| /... | |
| {% else %} | |
| {% set value = states(sensor_windspeed) %} | |
| {% set unit_of_measurement = state_attr(sensor_windspeed, 'unit_of_measurement') %} | |
| /{{ | |
| '...' if value in ('unavailable', 'unknown') | |
| else '%03d' | format(((value | float) * (0.6213 if unit_of_measurement == 'km/h' else 1)) | round | int) | |
| }} | |
| {% endif %} | |
| windgust: > | |
| {% if sensor_windgust == '' %} | |
| g... | |
| {% else %} | |
| {% set value = states(sensor_windgust) %} | |
| {% set unit_of_measurement = state_attr(sensor_windgust, 'unit_of_measurement') %} | |
| g{{ | |
| '...' if value in ('unavailable', 'unknown') | |
| else '%03d' | format(((value | float) * (0.6213 if unit_of_measurement == 'km/h' else 1)) | round | int) | |
| }} | |
| {% endif %} | |
| temp: > | |
| {% if sensor_temp == '' %} | |
| t... | |
| {% else %} | |
| {% set value = states(sensor_temp) %} | |
| {% set unit_of_measurement = state_attr(sensor_temp, 'unit_of_measurement') %} | |
| t{{ | |
| '...' if value in ('unavailable', 'unknown') | |
| else '%03d' | format(value | float | round | int) if unit_of_measurement == '°F' | |
| else '%03d' | format((((value | float) * 1.8) + 32) | round | int) | |
| }} | |
| {% endif %} | |
| hrrain: > | |
| {% if sensor_hrrain == '' %} | |
| r... | |
| {% else %} | |
| {% set value = states(sensor_hrrain) %} | |
| {% set unit_of_measurement = state_attr(sensor_hrrain, 'unit_of_measurement') %} | |
| r{{ | |
| '...' if value in ('unavailable', 'unknown') | |
| else '%03d' | format((((value | float) / (25.4 if unit_of_measurement == 'mm' else 1)) * 100) | round | int) | |
| }} | |
| {% endif %} | |
| twentyfourhrrain: > | |
| {% if sensor_twentyfourhrrain == '' %} | |
| p... | |
| {% else %} | |
| {% set value = states(sensor_twentyfourhrrain) %} | |
| {% set unit_of_measurement = state_attr(sensor_twentyfourhrrain, 'unit_of_measurement') %} | |
| p{{ | |
| '...' if value in ('unavailable', 'unknown') | |
| else '%03d' | format((((value | float) / (25.4 if unit_of_measurement == 'mm' else 1)) * 100) | round | int) | |
| }} | |
| {% endif %} | |
| dayrain: > | |
| {% if sensor_dayrain == '' %} | |
| P... | |
| {% else %} | |
| {% set value = states(sensor_dayrain) %} | |
| {% set unit_of_measurement = state_attr(sensor_dayrain, 'unit_of_measurement') %} | |
| P{{ | |
| '...' if value in ('unavailable', 'unknown') | |
| else '%03d' | format((((value | float) / (25.4 if unit_of_measurement == 'mm' else 1)) * 100) | round | int) | |
| }} | |
| {% endif %} | |
| humidity: > | |
| {% if sensor_humidity == '' %} | |
| h.. | |
| {% else %} | |
| {% set value = states(sensor_humidity) %} | |
| {% if value in ('unavailable', 'unknown') %} | |
| h.. | |
| {% else %} | |
| {% set filtered_value = value | float | round | int %} | |
| h{{ | |
| '..' if filtered_value < 1 else '00' if filtered_value == 100 else '%02d' | format(filtered_value) | |
| }} | |
| {% endif %} | |
| {% endif %} | |
| pressure: > | |
| {% if sensor_pressure == '' %} | |
| b..... | |
| {% else %} | |
| {% set value = states(sensor_pressure) %} | |
| {% set unit_of_measurement = state_attr(sensor_pressure, 'unit_of_measurement') %} | |
| b{{ | |
| '.....' if value in ('unavailable', 'unknown') | |
| else '%05d' | format(((value | float) * 338.639) | round | int) if unit_of_measurement not in ['mbar', 'hPa'] | |
| else '%05d' | format(((value | float) * 10) | round | int) | |
| }} | |
| {% endif %} | |
| luminosity: > | |
| {% if sensor_luminosity == '' %} | |
| L... | |
| {% else %} | |
| {% set value = states(sensor_luminosity) %} | |
| {% set unit_of_measurement = state_attr(sensor_luminosity, 'unit_of_measurement') %} | |
| {% if value in ('unavailable', 'unknown') %} | |
| L... | |
| {% else %} | |
| {% set converted_value = ((value | float) / (126.7 if unit_of_measurement == 'lux' else 1)) | round | int %} | |
| {% if converted_value < 1000 %} | |
| L{{ '%03d' | format(converted_value) }} | |
| {% else %} | |
| l{{ '%03d' | format(converted_value - 1000) }} | |
| {% endif %} | |
| {% endif %} | |
| {% endif %} | |
| action: | |
| - alias: 'Upload' | |
| if: > | |
| {{ | |
| host != '' | |
| and port != '' | |
| and callsign != '' | |
| and lat != '' | |
| and lon != '' | |
| }} | |
| then: | |
| - service: !input send_tcp_service | |
| data: | |
| host: !input host | |
| port: !input port | |
| packet: 'user {{ callsign }} pass -1 vers Python\n{{ callsign }}>APRS,TCPIP*:/{{ time }}h{{ lat }}/{{ lon }}{{ winddir }}{{ windspeed }}{{ windgust }}{{ temp }}{{ hrrain }}{{ twentyfourhrrain }}{{ dayrain }}{{ humidity }}{{ pressure }}{{ luminosity }}{{ station }}\n' | |
| - alias: 'Wait To Prevent Multiple Uploads' | |
| delay: | |
| seconds: '{{ delay | int }}' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I attempted setup of this Blueprint today, and I've got the send_tcp.sh script in the correct directory, but I am still getting the following error:
Error: [Errno 2] No such file or directory: '\\config\\blueprints\\automation\\sean6541\\send_t cp.sh'Here is my shell command:
shell_command: send_tcp: '/config/blueprints/automation/sean6541/send_tcp.sh {{ host }} {{ port }} "{{ packet }}"'And here is in the send_tcp.sh file:
#!/bin/bash printf "$3" | nc "$1" "$2"EDIT: I was able to get the below error fixed, the command "bash" needs to be used and I changed my directory as well. This is working:
shell_command: send_tcp: 'bash /share/cwop_upload/send_tcp.sh {{ host }} {{ port }} "{{ packet }}"'However I am now unsure if my data is actually making it to the CWOP servers.