/*
 * 
 *  Aurora Dimmer AU-A1ZB2WDM Driver
 *	
 */


@Field String driverVersion = "v1.08 (26th August 2023)"


#include BirdsLikeWires.library
import groovy.transform.Field

@Field boolean debugMode = false
@Field int reportIntervalMinutes = 10
@Field int checkEveryMinutes = 4


metadata {

	definition (name: "Aurora Dimmer AU-A1ZB2WDM", namespace: "BirdsLikeWires", author: "Andrew Davison", importUrl: "https://raw.githubusercontent.com/birdslikewires/hubitat/master/aurora/drivers/aurora_dimmer_a1zb2wdm.groovy") {

		capability "Actuator"
		capability "Configuration"
		capability "Light"
		capability "Refresh"
		capability "Switch"
		capability "SwitchLevel"

		command "indicatorOn"
		command "indicatorOff"

		attribute "healthStatus", "enum", ["offline", "online"]
		attribute "indicator", "enum", ["off", "on"]

		if (debugMode) {
			command "testCommand"
		}

		fingerprint profileId: "8E63", inClusters: "0000, 0003, 0004, 0005, 0006, 0008", outClusters: "0019", manufacturer: "Aurora", model: "WallDimmerMaster", deviceJoinName: "Aurora Dimmer AU-A1ZB2WDM"

	}

}


preferences {
	
	input name: "infoLogging", type: "bool", title: "Enable logging", defaultValue: true
	input name: "debugLogging", type: "bool", title: "Enable debug logging", defaultValue: true
	input name: "traceLogging", type: "bool", title: "Enable trace logging", defaultValue: true
	
}


void testCommand() {

	logging("${device} : Test Command", "info")

}


void configureSpecifics() {

	device.name = "Aurora Dimmer AU-A1ZB2WDM"

	int reportDelay = reportIntervalMinutes * 60

	ArrayList<String> cmds = []
	cmds += zigbee.configureReporting(0x0006, 0x0000, 0x10, 0, reportDelay)		// report 
	sendZigbeeCommands(cmds)

}


void updateSpecifics() {
	// Called by updated() method in BirdsLikeWires.library

	return

}


void refresh() {
	
	logging("${device} : Refreshing", "debug")
	sendZigbeeCommands([
		"he rattr 0x${device.deviceNetworkId} 0x01 0x0006 0x0000 {}",	// state
		"he rattr 0x${device.deviceNetworkId} 0x01 0x0008 0x0000 {}",	// level
		"he rattr 0x${device.deviceNetworkId} 0x03 0x0006 0x0000 {}"	// indicator state
	])

}


void off() {

	sendZigbeeCommands(["he cmd 0x${device.deviceNetworkId} 0x01 0x0006 0x00 {}"])
	//sendZigbeeCommands(zigbee.off())  // same thing

}


void on() {

	sendZigbeeCommands(["he cmd 0x${device.deviceNetworkId} 0x01 0x0006 0x01 {}"])
	//sendZigbeeCommands(zigbee.on())  // same thing

}


void indicatorOff() {

	// Turns blue backlight LED off. Does not persist with power cycling.
	sendZigbeeCommands(["he cmd 0x${device.deviceNetworkId} 0x03 0x0006 0x00 {}"])

}


void indicatorOn() {

	// Turns blue backlight LED on.
	sendZigbeeCommands(["he cmd 0x${device.deviceNetworkId} 0x03 0x0006 0x01 {}"])

}


void setLevel(BigDecimal level) {

	setLevel(level,1)

}


void setLevel(BigDecimal level, BigDecimal duration) {

	BigDecimal safeLevel = level <= 98 ? level : 100
	safeLevel = safeLevel < 0 ? 0 : safeLevel
	String hexLevel = percentageToHex(safeLevel.intValue())

	BigDecimal safeDuration = duration <= 25 ? (duration*10) : 255
	String hexDuration = Integer.toHexString(safeDuration.intValue())

	String pluralisor = duration == 1 ? "" : "s"
	logging("${device} : setLevel : Got level request of '${level}' (${safeLevel}%) [${hexLevel}] over '${duration}' (${safeDuration} decisecond${pluralisor}) [${hexDuration}].", "debug")

	// The command data is made up of three hex values, the first byte is the level, second is duration, third always seems to be '00'.
	sendZigbeeCommands(["he cmd 0x${device.deviceNetworkId} 0x01 0x0008 0x04 {${hexLevel} ${hexDuration} 00}"])

}


void checkLevel() {

	unschedule(checkLevel)
	logging("${device} : Checking Level", "debug")
	sendZigbeeCommands([
		"he rattr 0x${device.deviceNetworkId} 0x${device.endpointId} 0x0008 0x0000 {}"
	])

}


void parse(String description) {

	updateHealthStatus()
	checkDriver()

	Map descriptionMap = zigbee.parseDescriptionAsMap(description)

	if (descriptionMap) {

		logging("${device} : Parse : ${descriptionMap}", "debug")
		processMap(descriptionMap)

	} else {
		
		logging("${device} : Parse : Failed to parse received data. Please report these messages to the developer.", "warn")
		logging("${device} : Parse : ${description}", "error")

	}

}


void processMap(map) {

	if (map.cluster == "0006" || map.clusterId == "0006") {

		// On or off.

		String dimmerOrIndicator = (map.endpoint == "03" || map.sourceEndpoint == "03") ? "Indicator" : "Dimmer"

		String deviceData = (map.data != null) ? map.data[0] : ""

		if (map.value == "01" || deviceData == "01") {

			// On

			if (dimmerOrIndicator == "Dimmer") {

				sendEvent(name: "switch", value: "on")
				runIn(12, checkLevel)

			} else {

				sendEvent(name: "indicator", value: "on")

			}

			logging("${device} : ${dimmerOrIndicator} On", "info")

		} else if (map.value == "00" || deviceData == "00") {

			// Off

			if (dimmerOrIndicator == "Dimmer") {

				sendEvent(name: "switch", value: "off")
				runIn(12, checkLevel)

			} else {

				sendEvent(name: "indicator", value: "off")

			}

			logging("${device} : ${dimmerOrIndicator} Off", "info")

		} else {

			filterThis(map)

		}

	} else if (map.cluster == "0008" || map.clusterId == "0008") {

		// Level

		if (map.command == "01" || map.command == "0A") {

			// Reading

			int currentLevel = hexToPercentage("${map.value}")
			sendEvent(name: "level", value: "${currentLevel}")
			logging("${device} : Level : ${currentLevel}", "info")

		} else if (map.command == "0B") {

			// Status

			logging("${device} : fading", "debug")

		} else {

			filterThis(map)

		}

	} else {

		filterThis(map)

	}
	
}
