How to create automatic backups of hub database

Radio Stick has a DB of all the devices that have joined (paired). Using Third Party Tools, copying the DB to another stick is quite doable. I have two "extra" sticks and I update them within a week of adding a device.

However, it's not a duplicate. The extra sticks are secondary controllers in ZSpeak. That stick cannot be swapped into the hub. That's because there can be one and only one primary controller. The same Third Party Tools can be used to Transfer Primary, but that's still only half the battle. :frowning:

Although it's not mandatory, the final step is to get the new stick into Node 1. All of the Lifeline Associations point to #1. This involves (again) Third Party Tools to perform a "replace" on the Radio Stick you're replacing.

It’s not anyone’s fault, but I can’t help but think there might be a way to backup/clone the stick. If it’s truly not possible, or not on the roadmap, so be it. I don’t want to redesign the system, I just want to use it. If indeed HE is meant for the average mainstream consumer, telling them to rejoin/re-pair a good number of devices is not going to play well in that scenario. I moved all my stuff from ST basically in a day so I’m not sweating it. Having the backups is a HUGE reason I switched from ST and I’m glad they have the capability on HE.

I have to believe this set of Tool equivalences are planned but given the number of times we (combined) have to do that, I'm expecting it to be far down the priority list, although high on the FUN list. :smiley:

Because there are Third Party Tools to do it, yes, if this happens to you, you CAN get there from here... although I suspect that at the end.. you'll have wished you had just started over :slight_smile:

2 Likes

For any Windows O/S peeps out there, you can run a powershell script to back the hub up. This is a basic version of the script, and it does overwrite the backup each time. That is fixable. I'm pretty sure you can pass creds in it as well if you are using multiple accounts. Replace the bracketized details with yours. Add it to a scheduled task in Windows and you're good.
The Script(copy it into a file with extension .PS1):
Invoke-WebRequest -Uri "http://192.168.XXX.XXX/hub/backupDB?fileName=latest" -OutFile "<driveLetter>:\<folderName>\<fileName>"

The Arguments for the Task in Scheduler(These are based on my setup so change for yours):
-ExecutionPolicy Bypass -WindowStyle Hidden C:\Users\Daddio\Documents\hubitatBackup.ps1 -RunType $true

1 Like

I know how to make an exact copy of my z-wave db, but do you know how to make a copy of zigbee db? I have 3 combo sticks.

Have you tried any of the commercial cloning utilities?

I would love to know which one. I used a 3rd party app for z-wave but for zigbee I have no idea.

If you want unique file names for each backup you can do something like this:

$url = "http://192.168.XXX.XXX/hub/backupDB?fileName=latest"
$output = "C:\temp\hubitat backup $(get-date -f yyyy-MM-dd-HHmmss).lzf"

Invoke-WebRequest -Uri $url -OutFile $output
3 Likes

Zigbee's addressing is fixed. It isn't like ZWave where the node address gets assigned. Simply put, Zigbee devices are factory set with a unique address.

You can probably simply rejoin each Zigbee device and it will present to the new Radio Stick the same fixed address it presented to the old Radio Stick. In other words, to the Hub it will certainly retain the same address. Whether that's good enough.. a Zigbee nerd will need to voice.

Yeah, but you would still have to re-assign it to all your automations. If you remove a Zigbee device from Hubitat and then re-add it, it doesn't go back into all the automations it was in before. It may have the same addressing but it doesn't go into the same "slot" in the Hub that it was in before.

What's with this sudden bout of paranoia?

I wouldn't say paranoia, I purchased a full hub as backup just to be sure my home has security, I had weird problems with my hub so yes, I got precautions to have security all times, but that is my case, probably not the case to everyone else.

I will create a fun thread later with a bunch of crazy ideas I have... for security.

1 Like

@john.hart3706 and @SteveV - Thank you for the PowerShell script and Scheduled Task information. I now have automated backups running every day at 6:00 am.

2 Likes

This is essentially what I would be doing ... but enabling authentication breaks it.

Planning is not paranoia....it’s planning. If my hub died, I wouldn’t freak out if I had to recreate it from scratch. The backups are an excellent help.

As long as you're cool passing your password in plain text, this should work. Once authentication was turned on, HE now required stateful sessions.
This script is a .PS1 as well. I tested on my system and it fired off fine. Just update with your creds.
Let me know how all goes and if you need any 'tweaks'.

$Body = @{
    username = 'YOUR_NAME_HERE'
    password = 'YOUR_PW_HERE'
}
$url = "http://XXX.XXX.XXX.XXX/hub/backupDB?fileName=latest"
$output = "C:\YOURFOLDER\hubitat backup $(get-date -f yyyy-MM-dd-HHmmss).lzf"
$LoginResponse = Invoke-WebRequest 'http://XXX.XXX.XXX.XXX/login' -SessionVariable 'Session' -Body $Body -Method 'POST'

$Session

$ProfileResponse = Invoke-WebRequest $url -OutFile $output -WebSession $Session
$ProfileResponse
4 Likes

For those looking for the Curl way:

curl -c cookie.txt -d "username=myusername" -d "password=mypassword" http://{hub name or IP}/login
curl -sb cookie.txt http://{hub name or IP}/hub/backupDB?fileName=latest -o "/some/dir/myHubBackup$(date +%Y%m%d%H%M).lzf"

The first line hits the hub, does the login and saves the resulting JSESSIONID in a file called cookie.txt
The second line uses the saved JSESSIONID and causes the hub to build a backup file and downloads it under a filename with date&time appended.

1 Like

I've been following this thread with great interest. Seems that having a backup and replacing hub keeping the same stick is an easy recovery, however what happens when you have to replace the stick and rejoin all your devices?

Thanks @john.hart3706, I modified your PowerShell script to make it little bit more secure, configurable and added a retention policy, it will keep the last X backups and delete the rest, if less than X it will not delete any file...

$HubitatHost = "IP or Hostname"
$BackupPath = "Drive:\BackupFolder\SubFolder"
$RetentionPolicy = 30
$Protocol = "HTTPS"
$DisableCertificateValidation = $true


# Get Backup User Credentials
$BackupCredentials = "$BackupPath\BackupCredentials.xml"
If (!(Test-Path $BackupCredentials)) {
    $Credentials =  Get-Credential
    $Credentials | Export-CliXml -Path $BackupCredentials
} Else {
    Try {
        $Credentials = Import-CliXml -Path $BackupCredentials
    } Catch {
        Throw "Error reading credentials file, it may have been generatd with a diferent computer/account, try deleting the file and recreating it."
    }
}

# Sets Security Protocol to TLS 1.2 and certificate validation preference.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
If ($DisableCertificateValidation) { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } }

# Request Login Session
$Body = @{
    username = $Credentials.UserName
    password  = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credentials.Password)))
}

$url = "$Protocol`://$HubitatHost/hub/backupDB?fileName=latest"
$output = "$BackupPath\HubitatBackup_$(get-date -f yyyy-MM-dd-HHmmss).lzf"
$LoginResponse = Invoke-WebRequest "$Protocol`://$HubitatHost/login" -SessionVariable 'Session' -Body $Body -Method 'POST'

# Check if Login was successful
If ($LoginResponse.BaseResponse.ResponseUri -eq "$Protocol`://$HubitatHost/login") {
    Throw "Error Logging In to Hubitat, please check credentials."
}

# Download the Backup file
$ProfileResponse = Invoke-WebRequest $url -OutFile $output -WebSession $Session

# Apply Retention Policy
gci $BackupPath -Recurse| where {$_.extension -eq ".lzf" -and -not $_.PsIsContainer} | sort CreationTime -desc | select -Skip $RetentionPolicy | Remove-Item -Force

First time it runs it will ask for credentials and save them in an encrypted file with the backups. To change the credentials just delete the "BackupCredentials.xml" file and run manually again.

It will also check that it is able to login successfully or otherwise you'll end with a bunch of useless backup files containing the login page error.

Please note: The credentials file can only be used in the computer it was generated by the user who generated it. This will not stop anybody who knows what they’re doing from decrypting your password or from reusing your encrypted password if they are able to compromise your login. The whole point of converting your password to a SecureString and storing it in a file is to keep it out of plain text in your scripts so that it’s not as easily discovered.

Furthermore, because of the login mechanism currently implemented and the fact that Hubitat does not currently implement SSL, the password is still sent in plain text...

EDIT: Added support for HTTPS that was added to HE Firmware 2.0.5 but as the certificate is Self-Siged and does not include a host name, the script disables certificate validation. This is not ideal but much better as the password is not sent in clear text.

10 Likes

Very Cool! Now that looks like a complete solution. I Like It!!