UPDATED: Automating Unifi WiFi SSID password changes and QR code generation

I don’t know how I missed the colon. unfortunately, that didn’t fix it. I made sure that the user and password, and all other variables are correct.

new code

#!/bin/sh

cookie=$(mktemp)
headers=$(mktemp)

curl_cmd="curl --silent --output /dev/null --cookie ${cookie} --cookie-jar ${cookie} --insecure"

# generate new password
NEW_PWD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w 32 | head -n 1)

# generate QR code
wget --output-document="/config/www/${5}.png" "http://api.qrserver.com/v1/create-qr-code/?data=WIFI:T:WPA;S:${5};P:${NEW_PWD};H:;&size=100x100"

# authenticate against unifi controller
${curl_cmd} -H 'Content-Type: application/json' -D ${headers} -d "{\"username\":\"${1}\", \"password\":\"${2}\"}" https://${3}:8443/api/login

# change wifi password
${curl_cmd} -k -X PUT https://${3}:8443/api/s/default/rest/wlanconf/${4} -H "Content-Type: application/json" -d "{\"_id\":\"${4}\",\"x_passphrase\":\"${NEW_PWD}\"}"

error

stdout: ""
stderr: "/config/scripts/wifichange.sh: line 2: $'\\r': command not found\n/config/scripts/wifichange.sh: line 5: $'\\r': command not found\n/config/scripts/wifichange.sh: line 7: $'\\r': command not found\n/config/scripts/wifichange.sh: line 10: $'\\r': command not found\nConnecting to api.qrserver.com (95.216.163.127:80)\nwget: server returned error: HTTP/1.1 400 Bad Request\n/config/scripts/wifichange.sh: line 13: $'\\r': command not found\ncurl: option --insecure\r: is unknown\ncurl: try 'curl --help' or 'curl --manual' for more information\n/config/scripts/wifichange.sh: line 16: $'\\r': command not found\ncurl: option --insecure\r: is unknown\ncurl: try 'curl --help' or 'curl --manual' for more information"
returncode: 2

in my troubleshooting, I hardcoded the variable’s values and got the same error. then removed the unifi portion of the code and got this error

stdout: ""
stderr: |-
  /config/scripts/wifichange.sh: line 2: $'\r': command not found
  /config/scripts/wifichange.sh: line 5: $'\r': command not found
  /config/scripts/wifichange.sh: line 7: $'\r': command not found
  /config/scripts/wifichange.sh: line 10: $'\r': command not found
  Connecting to api.qrserver.com (159.69.246.187:80)
  wget: server returned error: HTTP/1.1 400 Bad Request
  /config/scripts/wifichange.sh: line 13: $'\r': command not found
  /config/scripts/wifichange.sh: line 16: $'\r': command not found
returncode: 127

I don’t know but it seems to me that the problem is in the QR code part

Looks like you have an extra character on every line, specifically \r.

You’ll need to open the script file in some type of editor that you show you non-printable characters to see it and remove it.

Actually, based on the line numbers, it looks like it’s complaining about every blank line. Just remove the blank lines and try that.

Hi @Laith_Alsunni ,

were you able to solve it?

thanks

i’m wanting to try to implement this on my system, but can i just check what the rationale is for using that online qr generator and the camera entity, rather than the new built in qr generator in the unifi integration? just want to make sure i’m understanding this whole thing correctly.

Scroll up.

i actually have read the whole thread but i noted you didn’t adjust your original code to use the built in unifi qr display so am curious if there’s a reason for this? is it just because its not giving you a .png that you can manipulate?

Hello,
after many days, I’m still not able to solve the return code 2 error.
i stumbled upon this GitHub - rootnegativ1/unifi-wifi: Home Assistant integration to change wireless passwords on UniFi Network controllers and seems to work really well. If anyone else wanna give it a try.

You read the whole thread?

So let me see if I have this straight - you’re asking me why I didn’t use the built-in integration that didn’t exist when I wrote this code, and was added because of the popularity of what I developed?

I don’t even know how to answer that.

yeah i did read the whole thread. before i posted. and again just in case after you replied.

and no, that’s not what i’m asking. I’m asking you if there’s a reason you aren’t using that built-in integration now that it exists. Because, i noticed you had updated your code as various comments came in through the thread and as you found ways to make it better. This part you didn’t update so I was wondering if you had a specific reason you preferred this and wanted to understand why it might be advantageous. That’s why i said i noticed you didn’t “update” your code to reflect it.

up to you if you want to answer the question, although i don’t get the passive aggression here. either way i appreciate your hard work on this it is great.

2 Likes

Ah. My apologies, I literally didn’t understand what you were asking. Not passive-aggressive, just extremely confused. LOL

Having said that, maybe you did read the entire thread, but I’m thinking you didn’t pay close enough attention to the dates.

My last update to the code was a full year before the integration was released, so… I guess now I find myself wondering why I would update my code to include code that is already part of an integration that can just easily be added without going through all the manual shenanigans I went through to make it work originally?

So yeah, I guess I’m still a bit confused by the question. LOL

If you want to use the integration, by all means - please do. In fact, I encourage it at this point. My code worked, but it was a bit “dirty”, since I’m not a full-time programmer like a lot of these guys are. I know enough to get by, but my formal education was a quarter century ago, and I ultimately went into the systems side of things, so I’ve only ever coded out of necessity, which is what this was.

The integration is much cleaner, and I presume will remain supported for some time to come. If it meets your needs, then I would absolutely go that route.

I continue to be humbled by the fact that my dirty old code written in my basement home office was the genesis for this feature addition to the official integration, but I’m a firm believer in “if it ain’t broke, don’t fix it”. It still works just fine in my environment, so… :wink:

Thank you for the kind words about my hard work, BTW. I definitely appreciate it.

1 Like

I should also add some password re-generation, I feel like that is the missing piece to offer a good guest experience :slight_smile:

I have iterated many times over the code to where it is now, I am only a coder by night and it’s been a long time since I worked as it. So don’t feel intimidated. It is really fun to work with home assistant.

Oh! I thought that had been added since it was a big part of what I wrote. Oh well, that’ll teach me to not test out the new stuff before recommending it as a full replacement! LOL

And yes, coding is fun, I agree - my issue is that once I get it working, I usually stop there. It could be ugly, inefficient, etc - but if it works, I’m happy. But that’s the difference between developing for yourself vs developing for someone else. :slight_smile:

For me its 50/50, I’m learning and having fun and at the same time users benefit and feedback.

got it. thanks for the info i’ll mess around with it and see how it goes! your code is still essential for the automating of changing the guest password so it’s much appreciated.

@Robban is there a way to access the png(or jpg) of the qr from the integration so it can be displayed however we want?

1 Like

I can’t get this custom component to work. I get error in log and don’t know how to find out what is wrong.

Logger: custom_components.unifi_wifi.coordinator
Source: helpers/update_coordinator.py:353
Integration: Unifi Wifi (documentation, issues)
First occurred: 10:52:00 (1 occurrences)
Last logged: 10:52:00

Authentication failed while fetching klubben319 data: {'meta': {'rc': 'error', 'msg': 'api.err.LoginRequired'}, 'data': []}

Posted here as well:

No idea what that is, but it’s not related at all to the topic of this thread.

Please do. I was digging through your integration for this kind of functionality when I came upon this.

EDIT: I did more reading, found out that the Home Assistant user for Unifi must have admin privileges to enable the QR code - not set as view only. That was the modification I had to make to my system to get it to show up.


Can anyone point me in the direction of how to implement this in the Unifi network integration? I can’t seem to find and documentation that really covers implementing the QR code, nor form looking around through the integration either.

If you mean the QR Code for the Wifi Password it’s a disabled image entity, which you first need to enable in the Unifi Integration menu.

Has anybody figured out an easy way to get the password from that QR Code and display it in a helper entity?

What i want to achive is a Wifi Guest Card on my Dashboard displaying the QR Code (-> image entity) + in clear text the wifi password if the QR Code is not working.

Currently i’m doing this with a shell_command, which is triggered after the last Guest is disconnecting and the regenerate password flow is initiated.
But i don’t know if there is an easier approach

shell_command:

#!/bin/sh
TOKEN=
SAVEDIR=/config/www/pictures/camera
FILENAME=guest-qr.jpg
PW=guest-pw.txt


# GET QR Code as JPG
curl -X GET https://hass.local/api/image_proxy/image.qr_code -H "Authorization: Bearer $TOKEN" --output $SAVEDIR/$FILENAME
sleep 2
# Decode QR Code and extract PW
zbarimg $SAVEDIR/$FILENAME | awk -F ":" '{print $6}' | sed 's/;//g' >> $SAVEDIR/$PW
WIFIPW=$(cat $SAVEDIR/$PW)

generate_post_data()
{
        cat <<EOF
{
        "entity_id": "input_text.guest_password",
        "value": "$WIFIPW"
}
EOF
}
# POST to push PW to HASS Service
curl -X POST https://hass.local/api/services/input_text/set_value -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" -d "$(generate_post_data)"

# CleanUp
rm -rf $SAVEDIR/$FILENAME
rm -rf $SAVEDIR/$PW

Automation:

alias: Refresh Wifi Guest Password
description: ""
trigger:
  - platform: numeric_state
    entity_id:
      - sensor.gast
    for:
      hours: 0
      minutes: 15
      seconds: 0
    below: 1
condition: []
action:
  - service: button.press
    target:
      entity_id: button.gast_regenerate_password
    data: {}
  - delay:
      hours: 0
      minutes: 0
      seconds: 30
      milliseconds: 0
  - service: shell_command.guest_qr_decode
    data: {}
mode: single