# ============================================================= # Parental Controls Package # Requires OPNsense firewall alias "parental_blocked" + rule # See README.md for full setup instructions # ============================================================= input_text: parental_control_config: name: Parental Controls Configuration max: 10000 initial: '{"users":[]}' icon: mdi:shield-account # ------------------------------------------------------------------ # OPNsense API calls # Secrets required in secrets.yaml — see secrets_example.yaml # ------------------------------------------------------------------ rest_command: parental_block_ip: url: !secret opnsense_alias_add_url method: post headers: Authorization: !secret opnsense_basic_auth payload: "address={{ address }}" content_type: "application/x-www-form-urlencoded" verify_ssl: false parental_unblock_ip: url: !secret opnsense_alias_del_url method: post headers: Authorization: !secret opnsense_basic_auth payload: "address={{ address }}" content_type: "application/x-www-form-urlencoded" verify_ssl: false parental_apply_firewall: url: !secret opnsense_apply_url method: post headers: Authorization: !secret opnsense_basic_auth payload: "{}" content_type: "application/json" verify_ssl: false # ------------------------------------------------------------------ # Scripts — called from the dashboard via HA WebSocket # ------------------------------------------------------------------ script: parental_block_ip: alias: "Parental Controls — Block IP" description: "Adds an IP to the OPNsense parental_blocked alias" icon: mdi:block-helper fields: ip: description: "IP address to block" required: true selector: text: sequence: - service: rest_command.parental_block_ip data: address: "{{ ip }}" parental_unblock_ip: alias: "Parental Controls — Unblock IP" description: "Removes an IP from the OPNsense parental_blocked alias" icon: mdi:check-circle-outline fields: ip: description: "IP address to unblock" required: true selector: text: sequence: - service: rest_command.parental_unblock_ip data: address: "{{ ip }}" parental_apply_firewall: alias: "Parental Controls — Apply Firewall" description: "Tells OPNsense to commit alias changes to the live firewall" icon: mdi:shield-refresh sequence: - service: rest_command.parental_apply_firewall # ------------------------------------------------------------------ # Optional: schedule enforcer automation # This runs every 5 minutes and enforces block schedules even when # the dashboard page isn't open. Enable by uncommenting below. # ------------------------------------------------------------------ # automation: # - id: parental_controls_schedule_enforcer # alias: "Parental Controls — Schedule Enforcer" # description: "Enforces scheduled blocks from the parental controls config" # trigger: # - platform: time_pattern # minutes: "/5" # condition: # - condition: template # value_template: > # {{ states('input_text.parental_control_config') not in ['unknown', 'unavailable', ''] }} # action: # - variables: # config: "{{ states('input_text.parental_control_config') | from_json }}" # is_weekend: "{{ now().weekday() >= 5 }}" # current_time: "{{ now().strftime('%H:%M') }}" # - repeat: # for_each: "{{ config.users }}" # sequence: # - variables: # user: "{{ repeat.item }}" # sched: "{{ repeat.item.schedule }}" # - condition: template # value_template: "{{ sched.enabled | default(false) }}" # - variables: # slot: "{{ sched.weekend if is_weekend else sched.weekday }}" # bt: "{{ slot.block_time }}" # ut: "{{ slot.unblock_time }}" # should_block: > # {% if bt == ut %} # false # {% elif bt < ut %} # {{ current_time >= bt and current_time < ut }} # {% else %} # {{ current_time >= bt or current_time < ut }} # {% endif %} # - repeat: # for_each: "{{ user.devices }}" # sequence: # - variables: # device: "{{ repeat.item }}" # dev_mac: "{{ device.mac | lower }}" # dev_ip: > # {% set trackers = states.device_tracker # | selectattr('attributes.mac', 'defined') | list %} # {% for t in trackers %} # {% set t_mac = (t.attributes.mac | default('')) | lower %} # {% if t_mac == dev_mac and t.attributes.ip is defined %} # {{ t.attributes.ip }}{% break %} # {% endif %} # {% endfor %} # - choose: # - conditions: # - condition: template # value_template: "{{ should_block and dev_ip | length > 0 }}" # sequence: # - service: script.parental_block_ip # data: # ip: "{{ dev_ip }}" # - conditions: # - condition: template # value_template: "{{ not should_block and dev_ip | length > 0 }}" # sequence: # - service: script.parental_unblock_ip # data: # ip: "{{ dev_ip }}" # - service: script.parental_apply_firewall