CAVEAT: The m1_FormatHubitatDeviceInfo macro in this post for cleaning up a copy of the Hubitat device table ONLY works when the device table is initially copied in the Firefox browser; the macro would have to be significantly re-worked if Chrome is used (I did not test any other browsers).
POST REVISED ON 2025-02-15
The Devices table in Hubitat has no apparent way to export itself to an Excel spreadsheet. However, the table can be selected, copied, and pasted into Excel -- with bad results in terms of formatting, handling of hex numbers, and preservation of links. [EDIT: but see post 5 below if you have a platform version preceding version 2.4.0.xxx.] I did come across a suggestion to paste the copied table into Google Sheets first, and then re-copy and paste into Excel -- this results in a somewhat more tractable spreadsheet (2-line items end up in the same cell), but a lot of manual formatting is needed to be presentable.
So I created a macro to ease things along, if you follow these steps exactly:
- In the Devices page of HE, select the setting "gear" icon, select "Display in list/table format", and select ONLY these items (note that "Type" will still be included in the table):
- "Show device IDs"
- "Show device name" [but not the toggle]
- "Show device network IDs"
- "Show device type"
- "Show device room" [but not the selection button]
- Back on the Devices page, place your cursor next to the word "Devices" at the very top of the table (above the table header row) and hit Ctr-A to select all.
- Hit Ctrl-C to copy the entire table.
- In a blank Google Sheets spreadsheet (free online), click on cell A1 and press Ctrl-V to paste the copied table.
- Immediately hit Ctrl-C to copy that pasted version of the table.
- In a blank Excel spreadsheet, click on cell A1 and press Ctrl-V to paste the table copied from Google Sheets.
- Save the spreadsheet in the macro-enabled format (.xlsm).
- Copy the VBA macro from below into that spreadsheet and run it (apologies for the weird bolding and text coloration in the code -- that's what the forum software does; however, pasting into VBA fixes all that).
You should get a nicely formatted sortable table with the ID, Label, Name, Type, Room, Device Network ID, and Zigbee ID values in separate columns (note that some devices do not follow the Device Network ID or Zigbee ID formats).
I don't know how to preserve the hyperlinks from the HE table -- they get messed up (missing or generally inaccurate) in the double-pasting process -- so I delete them.
NOTE WELL: The VBA code is mostly reliant on "dead reckoning" with respect to what cells, rows, columns, and cell values it expects to find values. This code works for me, BUT may not work for you.
Note also that Network IDs change from time to time (maybe from re-pairing them?), and that any cell in the DNI field that is longer than 4 characters is moved to the "Zigbee ID" field, as such values seem to be invariant (as opposed to Device Network IDs).
See also my m2_MatchAndHighlightDifferences VBA macro code in a later post for comparing old and new spreadsheets (within the same workbook) that have been processed by this macro. This second macro compares a "record" or initial copy of the device table in Excel to a second "new" copy of the device table and highlights the differences. Also posted below is a macro that copies changed Network IDs from the "new" spreadsheet to the "record" spreadsheet. It works for me, YMMV.
Here's a partial screen shot of the Excel spreadsheet I get for my HE Devices:
VBA CODE:
Sub m1_FormatHubitatDeviceInfo()
Dim vWorkSheet As Worksheet
Dim vCell As Range
Dim vLastRow As Long
Dim vLines As Variant
Dim vRow As Long
Dim vTable As ListObject
Dim vRange As Range
' set the variable vWorkSheet to the active work sheet
Set vWorkSheet = ActiveSheet
' delete all objects in the sheet and delete hyperlinks
For Each vShape In ActiveSheet.Shapes
vShape.Delete
Next vShape
' vWorkSheet.Cells.ClearFormats
'remove the hyperlinks because they are not all present & accurate after the pasting operation
vWorkSheet.Hyperlinks.Delete
' search for the first cell that contains "Compatible devices"
Set vCell = vWorkSheet.UsedRange.Find("Compatible devices", LookIn:=xlValues, LookAt:=xlPart)
If Not vCell Is Nothing Then
' delete all rows from the found cell upwards
vWorkSheet.Rows("1:" & vCell.Row).Delete
End If
' some special formating of certain columns as "TEXT" to prevent Excel from treating hex addresses like 0E65 as scientific notation numbers
Columns("B:G").Select
Selection.NumberFormat = "@"
' remove leading and trailing spaces
For Each vCell In vWorkSheet.UsedRange
If Not IsEmpty(vCell.Value) Then
vCell.Value = Trim(vCell.Value)
End If
Next vCell
' delete all blank rows
' find the last row with data
vLastRow = vWorkSheet.Cells(vWorkSheet.Rows.Count, "A").End(xlUp).Row
' loop from the last row to the first row
For vRow = vLastRow To 1 Step -1
' check if the entire row is blank
If Application.WorksheetFunction.CountA(vWorkSheet.Rows(vRow)) = 0 Then
' delete the blank row
vWorkSheet.Rows(vRow).Delete
End If
Next vRow
' insert a blank row at the top of the sheet
Rows("1:1").Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
' add 2 new columns
Columns("A:A").Insert Shift:=xlToRight ' insert a new column A to receive the ID info
Columns("C:C").Insert Shift:=xlToRight ' insert a new column C to receive the Name info
' some general initial formating
Columns("A:G").Select
Selection.ColumnWidth = 100 ' this value may have to be adjusted upward for very long Labels, Names, Types, etc.
' justify all cells to the top-left
With Selection
.HorizontalAlignment = xlLeft
.VerticalAlignment = xlTop
.Orientation = 0
.AddIndent = False
.IndentLevel = 0
.ShrinkToFit = False
.ReadingOrder = xlContext
.MergeCells = False
End With
Selection.Columns.AutoFit
Selection.Rows.AutoFit
vWorkSheet.Cells.Borders.LineStyle = xlNone
Columns("A").HorizontalAlignment = xlRight ' make column A right justified
' move the device ID number from column B to column A
' loop through each cell in column B
For Each vCell In vWorkSheet.UsedRange.Columns("B").Cells
' check if the cell contains a numeric value
If IsNumeric(vCell.Value) And Not IsEmpty(vCell.Value) Then
' copy the value and move it one column left and one row down
vCell.Offset(1, -1).Value = vCell.Value
' clear the original cell after moving the value
vCell.ClearContents
End If
Next vCell
' delete all blank rows
' find the last row with data
vLastRow = vWorkSheet.Cells(vWorkSheet.Rows.Count, "A").End(xlUp).Row
' loop from the last row to the first row
For vRow = vLastRow To 1 Step -1
' check if the entire row is blank
If Application.WorksheetFunction.CountA(vWorkSheet.Rows(vRow)) = 0 Then
' delete the blank row
vWorkSheet.Rows(vRow).Delete
End If
Next vRow
' find odd cases of ID numbers in column A that are BELOW their actual row data
' loop through rows
For Each vCell In vWorkSheet.UsedRange.Columns("A").Cells
' check if the cell in column A is blank and the cell below contains a numeric value
If IsEmpty(vCell.Value) And IsNumeric(vCell.Offset(1, 0).Value) And Not IsEmpty(vCell.Offset(1, 0).Value) Then
' move the numeric value to the blank cell
vCell.Value = vCell.Offset(1, 0).Value
vCell.Offset(1, 0).ClearContents
End If
' check if the cell in column B is blank and delete it if true
If IsEmpty(vCell.Offset(0, 1).Value) Then
vCell.Offset(0, 1).Delete Shift:=xlShiftToLeft
' move the contents of column C to column B
vCell.Offset(0, 1).Value = vCell.Offset(0, 2)
vCell.Offset(0, 2).ClearContents
End If
' if the next row is now empty, delete the row
If Application.WorksheetFunction.CountA(Rows(vCell.Offset(1, 0).Row)) = 0 Then
vWorkSheet.Rows(vCell.Offset(1, 0).Row).Delete
End If
Next vCell
' process the Label/Name column, splitting rows with 2 line into 2 columns, B and C
' loop through each cell in column B
For Each vCell In vWorkSheet.UsedRange.Columns("B").Cells
' check if the cell contains line breaks (i.e., multiple lines)
If InStr(vCell.Value, Chr(10)) > 0 Then
' split the cell content into lines using the line break (Chr(10))
vLines = Split(vCell.Value, Chr(10))
' If there are two or more lines, move the second line to column C
If UBound(vLines) >= 1 Then
' move the second line to column C
vCell.Offset(0, 1).Value = vLines(1) ' This moves the second line to column C
' remove the second line from the original cell
vCell.Value = vLines(0) ' Retain only the first line in the original cell
End If
End If
Next vCell
' process the DNI column, splitting rows with 2 line into 2 columns, F and G
' loop through each cell in column F
For Each vCell In vWorkSheet.UsedRange.Columns("F").Cells
' check if the cell contains line breaks (i.e., multiple lines)
If InStr(vCell.Value, Chr(10)) > 0 Then
' split the cell content into lines using the line break (Chr(10))
vLines = Split(vCell.Value, Chr(10))
' if there are two or more lines, move the second line to the next column (G)
If UBound(vLines) >= 1 Then
' move the second line to the next column (B)
vCell.Offset(0, 1).Value = vLines(1) ' This moves the second line to column G
' remove the second line from the original cell
vCell.Value = vLines(0) ' Retain only the first line in the original cell
End If
End If
Next vCell
' for rows with blank Label and Name values, delete the Label cell and move rest of the row left
' loop through each cell in columns B and C
For Each vCell In vWorkSheet.UsedRange.Columns("B").Cells
If IsEmpty(vCell.Value) And IsEmpty(vCell.Offset(0, 1).Value) Then
vCell.Delete Shift:=xlToLeft
End If
Next vCell
' for each Name in column C that is blank, copy the Label from column B
' loop through each cell in column C
For Each vCell In vWorkSheet.UsedRange.Columns("C").Cells
' check if the cell in column C is blank
If IsEmpty(vCell.Value) Then
' copy the value from column B
vCell.Value = vCell.Offset(0, -1).Value
End If
Next vCell
' OPTIONAL: move all long (>4 characters) DNI column values to the Zigbee ID colum
' loop through each cell in column F
For Each vCell In vWorkSheet.UsedRange.Columns("F").Cells
' check if the cell in column F is longer than 4 characters
If Len(vCell) > 4 Then
' copy the value to column G
vCell.Offset(0, 1).Value = vCell.Value
' insert a hyphen character in the original cell in column F
vCell.Value = "-"
End If
Next vCell
' delete all blank rows
' find the last row with data
vLastRow = vWorkSheet.Cells(vWorkSheet.Rows.Count, "A").End(xlUp).Row
' loop from the last row to the first row
For vRow = vLastRow To 1 Step -1
' check if the entire row is blank
If Application.WorksheetFunction.CountA(vWorkSheet.Rows(vRow)) = 0 Then
' delete the blank row
vWorkSheet.Rows(vRow).Delete
End If
Next vRow
' insert a header row
Rows("1:1").Select
Selection.Insert Shift:=xlDown, CopyOrigin:=xlFormatFromLeftOrAbove
Range("A1").Select
ActiveCell.FormulaR1C1 = "ID"
Range("B1").Select
ActiveCell.FormulaR1C1 = "Label"
Range("C1").Select
ActiveCell.FormulaR1C1 = "Name"
Range("D1").Select
ActiveCell.FormulaR1C1 = "Type"
Range("E1").Select
ActiveCell.FormulaR1C1 = "Room"
Range("F1").Select
ActiveCell.FormulaR1C1 = "Net ID"
Range("G1").Select
ActiveCell.FormulaR1C1 = "Zigbee ID"
' OPTIONAL: apply a table style
' define the data range (modify as needed)
' find the last row with data
vLastRow = vWorkSheet.Cells(vWorkSheet.Rows.Count, "A").End(xlUp).Row
Set vRange = vWorkSheet.Range("A1:G" & vLastRow)
' ensure there is data in the range
If vRange.Rows.Count = 1 And vRange.Cells(1, 1).Value = "" Then Exit Sub
' check if a table already exists in the range
On Error Resume Next
Set vTable = vWorkSheet.ListObjects(1) ' assuming there's only one table in the sheet
On Error GoTo 0
' if no table exists, create one
If vTable Is Nothing Then
Set vTable = vWorkSheet.ListObjects.Add(xlSrcRange, vRange, , xlYes) ' xlYes assumes headers exist
End If
' apply a table style (modify the style name as needed)
vTable.TableStyle = "TableStyleLight7"
' some final formatting
Columns("A:G").Select
Selection.ClearFormats
With Selection.Font
.Name = "Calibri"
.Size = 11
.ColorIndex = xlAutomatic
.TintAndShade = 0
.Underline = xlUnderlineStyleNone
.Italic = False
.Strikethrough = False
.Superscript = False
.Subscript = False
.OutlineFont = False
.Shadow = False
.ThemeFont = xlThemeFontMinor
End With
Selection.Columns.AutoFit
Selection.Rows.AutoFit
' color the header row yellow and bold the text
Range("A1:G1").Select
With Selection.Interior
.Pattern = xlSolid
.PatternColorIndex = xlAutomatic
.Color = 65535
.TintAndShade = 0
.PatternTintAndShade = 0
End With
Selection.Font.Bold = True
' freeze the top row
With ActiveWindow
.SplitColumn = 0
.SplitRow = 1
.FreezePanes = True
End With
' position the cursor at the head of the Label column and turn on the AutoFilter function
Range("B1").Select
Selection.AutoFilter
End Sub
2025-02-15: EDITED post to provide the most recent VBA macro and examples.