Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@
package org.openhab.binding.zigbee.firmware;

import java.io.File;
import java.io.InputStream;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
Expand Down Expand Up @@ -47,20 +48,28 @@
public class ZigBeeFirmwareProvider implements FirmwareProvider {
private Logger logger = LoggerFactory.getLogger(ZigBeeFirmwareProvider.class);

private final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);

private GithubLibraryReader directoryReader;
private Set<GithubLibraryReader> directoryReaders = new HashSet<>();

@Activate
protected void activate() {
protected void activate() throws Exception {
logger.debug("ZigBee Firmware Provider: Activated");

String folder = OpenHAB.getUserDataFolder() + File.separator + "firmware" + File.separator;
GithubLibraryReader directoryReader;

directoryReader = new GithubLibraryReader(folder);
try {
directoryReader.create("https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master");
directoryReader.updateRemoteDirectory();
directoryReader.create("https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index.json");
directoryReaders.add(directoryReader);
} catch (Exception e) {
logger.error("Exception activating ZigBee firmware provider ", e);
logger.error("Exception activating ZigBee upgrade firmware provider ", e);
}
directoryReader = new GithubLibraryReader(folder);
try {
directoryReader.create("https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/index1.json");
directoryReaders.add(directoryReader);
} catch (Exception e) {
logger.error("Exception activating ZigBee downgrade firmware provider ", e);
}
}

Expand All @@ -76,20 +85,43 @@ protected void deactivate() {

@Override
public @Nullable Firmware getFirmware(@NonNull Thing thing, @NonNull String version, @Nullable Locale locale) {
ZigBeeFirmwareVersion requestedVersion = getRequestedVersionFromThing(thing);
if (requestedVersion == null) {
ZigBeeFirmwareVersion deviceVersion = getThingRequestedVersion(thing);
if (deviceVersion == null) {
return null;
}

List<DirectoryFileEntry> directory = directoryReader.getDirectory();
for (DirectoryFileEntry firmware : directory) {
if (firmware.getFirmwareVersion().equals(requestedVersion)) {
return getZigBeeFirmware(thing.getThingTypeUID(), firmware);
int specificVersion;
try {
specificVersion = Integer.parseInt(version);
} catch (NumberFormatException e) {
logger.info("ZigBee Firmware Provider: Requested version {} for {} is not an integer", version,
thing.getUID());
return null;
}
logger.debug("ZigBee Firmware Provider: Getting version {} of {}", specificVersion, thing.getUID());

GithubLibraryReader directoryReader = null;
DirectoryFileEntry directory = null;
for (GithubLibraryReader reader : directoryReaders) {
directory = reader.getDirectoryEntry(deviceVersion, specificVersion);
if (directory != null) {
logger.debug("ZigBee Firmware Provider: Firmware available from {}", reader.getRepositoryAddress());
directoryReader = reader;
break;
}
}

logger.debug("Unable to find firmware version {}", version);
return null;
if (directory == null || directoryReader == null) {
logger.debug("ZigBee Firmware Provider: Firmware not found");
return null;
}

InputStream inputStream = directoryReader.getInputStream(directory);
if (inputStream == null) {
return null;
}

return getZigBeeFirmware(thing.getThingTypeUID(), directory, inputStream);
}

@Override
Expand All @@ -99,34 +131,48 @@ protected void deactivate() {

@Override
public @Nullable Set<@NonNull Firmware> getFirmwares(@NonNull Thing thing, @Nullable Locale locale) {
final Set<Firmware> firmwareSet = new HashSet<>();

ZigBeeFirmwareVersion requestedVersion = getRequestedVersionFromThing(thing);
ZigBeeFirmwareVersion requestedVersion = getThingRequestedVersion(thing);
if (requestedVersion == null) {
return firmwareSet;
return Collections.emptySet();
}

for (DirectoryFileEntry firmware : directoryReader.getDirectory()) {
if (firmware.getFirmwareVersion().equals(requestedVersion)) {
firmwareSet.add(getZigBeeFirmware(thing.getThingTypeUID(), firmware));
}
final Set<DirectoryFileEntry> directorySet = new HashSet<>();
for (GithubLibraryReader reader : directoryReaders) {
directorySet.addAll(reader.getDirectorEntries(requestedVersion));
}

final Set<Firmware> firmwareSet = new HashSet<>();
for (DirectoryFileEntry firmware : directorySet) {
firmwareSet.add(getZigBeeFirmware(thing.getThingTypeUID(), firmware));
}

logger.debug("ZigBee Firmware Provider: Thing {} has {} firmwares available", thing.getUID(),
firmwareSet.size());
return firmwareSet;
}

private ZigBeeFirmwareVersion getRequestedVersionFromThing(@NonNull Thing thing) {
private ZigBeeFirmwareVersion getThingRequestedVersion(@NonNull Thing thing) {
// We only deal in ZigBee devices here
if (!(thing.getHandler() instanceof ZigBeeThingHandler)) {
return null;
}
logger.debug("ZigBee Firmware Provider: Getting requested version of {}", thing.getUID());
ZigBeeThingHandler zigbeeHandler = (ZigBeeThingHandler) thing.getHandler();
if (zigbeeHandler == null) {
logger.info("ZigBee Firmware Provider: No handler found for {}", thing.getUID());
return null;
}
return zigbeeHandler.getRequestedFirmwareVersion();
ZigBeeFirmwareVersion version = zigbeeHandler.getRequestedFirmwareVersion();
logger.debug("ZigBee Firmware Provider: Requested version of {} is {}", thing.getUID(), version);
return version;
}

private Firmware getZigBeeFirmware(@NonNull ThingTypeUID thingTypeUID, DirectoryFileEntry directoryEntry) {
return getZigBeeFirmware(thingTypeUID, directoryEntry, null);
}

private Firmware getZigBeeFirmware(@NonNull ThingTypeUID thingTypeUID, DirectoryFileEntry directoryEntry,
InputStream inputStream) {
FirmwareBuilder builder = FirmwareBuilder.create(thingTypeUID, directoryEntry.getVersion().toString());

if (!directoryEntry.getModel().isEmpty()) {
Expand All @@ -138,13 +184,31 @@ private Firmware getZigBeeFirmware(@NonNull ThingTypeUID thingTypeUID, Directory
if (!directoryEntry.getDescription().isEmpty()) {
builder.withDescription(directoryEntry.getDescription());
}
if (!directoryEntry.getReleaseNotes().isEmpty()) {
builder.withChangelog(directoryEntry.getReleaseNotes());
}
if (!directoryEntry.getMd5().isEmpty()) {
builder.withMd5Hash(directoryEntry.getMd5());
}
if (!directoryEntry.getPrerequisiteVersion().isEmpty()) {
builder.withPrerequisiteVersion(directoryEntry.getPrerequisiteVersion());
}

if (inputStream != null) {
builder.withInputStream(inputStream);
}

Map<String, String> properties = new HashMap<>();

if (directoryEntry.getFilesize() != null) {
properties.put("Filesize", directoryEntry.getFilesize().toString());
}
if (directoryEntry.getFilename() != null) {
properties.put("Filename", directoryEntry.getFilename());
}

builder.withProperties(properties);

return builder.build();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.binding.zigbee.firmware.internal;

/**
* Contains the information describing a firmware directory entry
*
* @author Chris Jackson
*
*/
public class DirectoryEntry {

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
* @author Chris Jackson
*
*/
public class DirectoryFileEntry {
public class DirectoryFileEntry extends DirectoryEntry {
private String fileName;
private Integer manufacturerCode;
private Integer imageType;
private Integer fileVersion;
Expand All @@ -32,17 +33,35 @@ public class DirectoryFileEntry {
private String modelId;
private String url;

private String otaHeaderString;

private Boolean force;
private Integer hardwareVersionMin;
private Integer hardwareVersionMax;
private Integer minFileVersion;
private Integer maxFileVersion;
private String originalUrl;
private String releaseNotes;

// OH internal
private String thingTypeUid;
private String prerequisiteVersion;
private String model;
private String vendor;
private String description;
private String md5;

/**
* @return the filename
*/
public String getFilename() {
return fileName;
}

/**
* @return the fileSize
*/
public Integer getFileSize() {
public Integer getFilesize() {
return fileSize;
}

Expand Down Expand Up @@ -74,20 +93,6 @@ public String getSha512() {
return sha512;
}

/**
* @return the filesize
*/
public Integer getFilesize() {
return fileSize;
}

/**
* @param filesize the filesize to set
*/
public void setFilesize(Integer filesize) {
this.fileSize = filesize;
}

/**
* @return the thingTypeUid
*/
Expand Down Expand Up @@ -120,7 +125,13 @@ public String getVendor() {
* @return the description
*/
public String getDescription() {
return description == null ? "" : description;
if (description != null) {
return description;
}
if (otaHeaderString != null) {
return otaHeaderString;
}
return null;
}

/**
Expand Down Expand Up @@ -156,38 +167,72 @@ public List<String> getManufacturerName() {
}

/**
* @param manufacturerName the manufacturerName to set
* @return the modelId
*/
public void setManufacturerName(List<String> manufacturerName) {
this.manufacturerName = manufacturerName;
public String getModelId() {
return modelId == null ? "" : modelId;
}

/**
* @return the modelId
* @return the url
*/
public String getModelId() {
return modelId;
public String getUrl() {
return url;
}

/**
* @param modelId the modelId to set
* @return the otaHeaderString
*/
public void setModelId(String modelId) {
this.modelId = modelId;
public String getOtaHeaderString() {
return otaHeaderString;
}

/**
* @return the url
* @return the force
*/
public String getUrl() {
return url;
public Boolean getForce() {
return force == null ? Boolean.FALSE : force;
}

/**
* @return the hardwareVersionMin
*/
public Integer getHardwareVersionMin() {
return hardwareVersionMin;
}

/**
* @return the hardwareVersionMax
*/
public Integer getHardwareVersionMax() {
return hardwareVersionMax;
}

/**
* @param url the url to set
* @return the minFileVersion
*/
public void setUrl(String url) {
this.url = url;
public Integer getMinFileVersion() {
return minFileVersion;
}

/**
* @return the maxFileVersion
*/
public Integer getMaxFileVersion() {
return maxFileVersion;
}

/**
* @return the originalUrl
*/
public String getOriginalUrl() {
return originalUrl;
}

/**
* @return the releaseNotes
*/
public String getReleaseNotes() {
return releaseNotes == null ? "" : releaseNotes;
}
}
Loading
Loading