Skip to content

Commit

Permalink
More robustness in changing IPs, reconnecting
Browse files Browse the repository at this point in the history
  • Loading branch information
ChrisTerBeke committed Apr 25, 2024
1 parent 314cd34 commit 782d749
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 50 deletions.
4 changes: 2 additions & 2 deletions app.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,12 @@
{
"id": "address",
"label": {
"en": "IP Address"
"en": "Override IP Address"
},
"type": "text",
"required": false,
"hint": {
"en": "The IP address of the device."
"en": "Overrides the auto-discovered IP address of the device."
}
}
]
Expand Down
71 changes: 41 additions & 30 deletions drivers/uponor/device.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,93 +9,104 @@ class UponorThermostatDevice extends Device {

private _syncInterval?: NodeJS.Timer
private _client?: UponorHTTPClient
async onInit() {

async onInit(): Promise<void> {
this.registerCapabilityListener('target_temperature', this._setTargetTemperature.bind(this))
// this.registerCapabilityListener('thermostat_mode', this._setThermostatMode.bind(this))
this._init()
}

async onAdded(): Promise<void> {
await this._init()
this._init()
}

async onUninit(): Promise<void> {
await this._uninit()
this._uninit()
}

onDiscoveryResult(discoveryResult: DiscoveryResult) {
onDiscoveryResult(discoveryResult: DiscoveryResult): boolean {
return this.getData().id.includes(discoveryResult.id)
}

async onDiscoveryAvailable(discoveryResult: DiscoveryResultMAC) {
await this._updateAddress(discoveryResult.address)
async onDiscoveryAvailable(discoveryResult: DiscoveryResultMAC): Promise<void> {
this._updateAddress(discoveryResult.address)
}

async onDiscoveryAddressChanged(discoveryResult: DiscoveryResultMAC): Promise<void> {
await this._updateAddress(discoveryResult.address)
this._updateAddress(discoveryResult.address)
}

async onDiscoveryLastSeenChanged(discoveryResult: DiscoveryResultMAC): Promise<void> {
await this._updateAddress(discoveryResult.address)
this._updateAddress(discoveryResult.address)
}

async onSettings({ newSettings }: { newSettings: { [key: string]: any } }): Promise<void> {
const addressUpdated = await this._updateAddress(newSettings.address as string)
if (!addressUpdated) {
throw new Error(`Could not connect to Uponor controller on IP address ${newSettings.address}`)
}
}

async onDeleted(): Promise<void> {
await this._uninit()
this._uninit()
}

private _getAddress(): string {
private _getAddress(): string | undefined {
const settingAddress = this.getSetting('address')
if (settingAddress) return settingAddress
const storeAddress = this.getStoreValue('address')
if (storeAddress) return storeAddress
return ""
return undefined
}

private async _updateAddress(newAddress: string) {
private async _updateAddress(newAddress: string): Promise<boolean> {
const client = new UponorHTTPClient(newAddress)
const connected = await client.testConnection()
if (!connected) {
await this.setUnavailable(`Could not find Uponor controller on IP address ${newAddress}`)
return
}
await this.setStoreValue('address', newAddress)
await this._init()
const canConnect = await client.testConnection()
if (!canConnect) return false
this.setStoreValue('address', newAddress)
this._init()
return true
}

async _init(): Promise<void> {
await this._uninit()
const address = this._getAddress()
this._client = new UponorHTTPClient(address)
if (!address) return this.setUnavailable('No IP address configured')
const client = new UponorHTTPClient(address)
const canConnect = await client.testConnection()
if (!canConnect) return this.setUnavailable(`Could not connect to Uponor controller on IP address ${address}`)
this._client = client
this._syncInterval = setInterval(this._syncAttributes.bind(this), POLL_INTERVAL_MS)
await this._syncAttributes()
await this.setAvailable()
this._syncAttributes()
}

async _uninit() {
async _uninit(): Promise<void> {
this.setUnavailable()
clearInterval(this._syncInterval as NodeJS.Timeout)
this._syncInterval = undefined
this._client = undefined
}

private async _syncAttributes() {
if (!this._client) return
private async _syncAttributes(): Promise<void> {
if (!this._client) return this.setUnavailable('No Uponor client')
await this._client.syncAttributes()
const { controllerID, thermostatID } = this.getData()
const data = this._client.getThermostat(controllerID, thermostatID)
if (!data) return
if (!data) return this.setUnavailable('Could not find thermostat data')
this.setAvailable()
this.setCapabilityValue('measure_temperature', data.temperature)
this.setCapabilityValue('target_temperature', data.setPoint)
// this.setCapabilityValue('thermostat_mode', data?.mode)
// this.setCapabilityValue('thermostat_mode', data.mode)
}

private async _setTargetTemperature(value: number) {
private async _setTargetTemperature(value: number): Promise<void> {
if (!this._client) return
const { controllerID, thermostatID } = this.getData()
await this._client.setTargetTemperature(controllerID, thermostatID, value)
await this._syncAttributes()
}

private async _setThermostatMode(value: Mode) {
private async _setThermostatMode(value: Mode): Promise<void> {
if (!this._client) return
const { controllerID, thermostatID } = this.getData()
await this._client.setMode(controllerID, thermostatID, value)
Expand Down
4 changes: 2 additions & 2 deletions drivers/uponor/driver.compose.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@
{
"id": "address",
"label": {
"en": "IP Address"
"en": "Override IP Address"
},
"type": "text",
"required": false,
"hint": {
"en": "The IP address of the device."
"en": "Overrides the auto-discovered IP address of the device."
}
}
]
Expand Down
17 changes: 8 additions & 9 deletions drivers/uponor/pair/start.html
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
<script type="application/javascript">
Homey.setTitle("Uponor setup")
Homey.setSubtitle("Select the pairing method")

function setCustomIP() {
var address = document.getElementById("address").value
Homey.emit("custom_ip_address", address)
}
</script>

<p>
Automated discovery mode scans for known Uponor devices in the local network.
This does not always work depending on the network configuration.
If you do not see your Uponor devices in the list, please try entering the IP address before continuing.
</p>
<header class="homey-header">
<h1 class="homey-title" data-i18n="pair.title"></h1>
<p class="homey-subtitle" data-i18n="pair.subtitle"></p>
</header>

<p data-i18n="pair.description"></p>

<p data-i18n="pair.custom_ip_address_warning" style="color: orange;"></p>

<form class="homey-form">
<fieldset class="homey-form-fieldset">
<div class="homey-form-group">
<label class="homey-form-label" for="address">IP Address</label>
<label class="homey-form-label" for="address" data-i18n="pair.ip_address"></label>
<input class="homey-form-input" id="address" type="text" value="" onblur="setCustomIP()" />
</div>
</fieldset>
Expand Down
17 changes: 11 additions & 6 deletions lib/UponorHTTPClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,17 @@ export class UponorHTTPClient {
}

public async testConnection(): Promise<boolean> {
const request = await fetch(this._url, {
method: 'POST',
headers: { 'x-jnap-action': 'http://phyn.com/jnap/uponorsky/GetAttributes' },
body: '{}'
})
return request.status == 200
try {
const request = await fetch(this._url, {
method: 'POST',
headers: { 'x-jnap-action': 'http://phyn.com/jnap/uponorsky/GetAttributes' },
body: '{}',
timeout: 3000,
})
return request.status == 200
} catch (error) {
return false
}
}

private async _syncAttributes(): Promise<Map<string, string>> {
Expand Down
10 changes: 9 additions & 1 deletion locales/en.json
Original file line number Diff line number Diff line change
@@ -1 +1,9 @@
{}
{
"pair": {
"title": "Uponor setup",
"subtitle": "Select the pairing method",
"description": "Homey scans for known Uponor devices in the local network. This does not always work depending on the network configuration. If you do not see your Uponor devices in the list, please try entering the IP address before continuing.",
"ip_address": "IP address",
"custom_ip_address_warning": "Automatic discovery is recommended to prevent issues when the IP address of the controller changes."
}
}

0 comments on commit 782d749

Please sign in to comment.