Fibaro FGMS-001 odd behaviour

Morning,

I recently purchased a set of second hand Fibaro FGMS-001 motion / vibration / illuminance sensors to use for my home alarm system and lighting scenes. I paired them with the Hubitat no problems, and all 5 were automatically detected and used the 'Fibaro ZW5 motion sensor' driver. So far so good.

However, i noticed a few strange things. First, the wake up period of the device (default 2 hours) was set by hubitat to 12 hours at first connection. I dont see any way to change that to something more frequent when looking at the parameters i can adjust.

Whilst that's not a problem, it does have relevance to the other issues i have. Motion detection works absolutely fine, but illuminance reports only come through when the devices wake up and contacts hubitat. according to the read states of illuminance threshold and time period for illuminance reporting it should report changes of 100 lux or every 2 hours. None of them do; it just happens at wakeup every 12 hours (at which point it does report a reasonable value). Temperature and vibration monitoring work fine, though I've disabled them as dont need them.

I'm not sure if it is relevant, but the devices all state that there are 2 changes pending in the logs which never clear. If i make more changes to the config the number increases until next wakeup, then it applies the changes and goes back to 2. I dont know what those 2 changes are!

Reading through the forums there are other cases of issues with these sensors, but nothing i could see that tied in with my particular problems.

Being second hand i've no idea what firmware they are, if that matters. either way its a systematic issue that affects all five of the sensors.

Anybody any thoughts? I'm running out of ideas....

screenshot|690x388

Sounds like you could have the version 1's they are not z-wave plus and seem to have a few quirks.
I have four of these which i couldn't get working properly with the inbuilt driver or others posted in the community, so i used this to learn about writing drivers and have managed to get them to work reasonably well now.

This is the driver i have, might be worth ago to see if it helps.
The four i have do not actually wake up when pressing the button in side so you do have to wait for them to wake up naturally

/*
  Fibaro Motion Sensor FGMS-001

  Based on code from the multiple people from the Hubitat Community and reference drivers from Hubitat
  These include but not limited to 
    Jean-Jacques GUILLEMAUD, Artur Draga, Bryan Turcotte, Robin Winbourne, Eric Maycock

  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
  in compliance with the License. You may obtain a copy of the License at:
 
  http://www.apache.org/licenses/LICENSE-2.0
 
  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  for the specific language governing permissions and limitations under the License.

*/

metadata {
	definition (name: "Fibaro Motion Sensor FGMS-001 ", namespace: "entire", author: "Entire") {
		capability "Battery"
		capability "Illuminance Measurement"
		capability "Motion Sensor"
		capability "Sensor"
		capability "Tamper Alert"
		capability "Temperature Measurement"

		fingerprint mfr: "010F", deviceId: "0x1001", inClusters: "0x30,0x84,0x85,0x80,0x8F,0x56,0x72,0x86,0x70,0x8E,0x31,0x9C"
	}
	
	preferences {
    parameterMap().each {
      input it.name, it.type, title:it.title, options:it.items, range:(it.min != null && it.max != null) ? "${it.min}..${it.max}" : null, defaultValue:it.default, required: false
    }
	}
}

/////////////////////////////////////////////////////
// Parameters 
private parameterMap() {[
	[name:"wakeUpInterval", mode:"settings", type:"number", default:7200, min:1, max:65535, title:"Wake Up interval in seconds (default 7200)"], 
	[name:"p1", index:1, mode:"zwave", size:1, type:"number", default:15, min:8, max:255, title:"Sensitivity. Default 10 (8-255)"], 
	[name:"p2", index:2, mode:"zwave", size:1, type:"number", default:15, min:0, max:15, title:"Motion blind time. Default 15 (0 - 15)"], 
	[name:"p3", index:3, mode:"zwave", size:1, type:"enum", default:1, min:0, max:3, title:"Movement pulse count.", items:[0:"1", 1:"2 (default)", 2:"3", 3:"4", 4:"5"]],
	[name:"p4", index:4, mode:"zwave", size:1, type:"enum", default:2, min:0, max:3, title:"Window time", items:[0: "4s", 1: "8s", 2: "12s (default)", 3: "16s"]], 
	[name:"p6", index:6, mode:"zwave", size:2, type:"number", default:30, min:1, max:65535, title:"Motion cancel time"], 
	[name:"p8", index:8, mode:"zwave", size:1, type:"enum", default:0, min:0, max:2, title:"PIR Operating Mode", items:[0: "Always active (default)", 1: "Active during day", 2: "Active during night"]], 
	[name:"p9", index:9, mode:"zwave", size:2, type:"number", default:200, min:1, max:65535, title:"Night / day light intensity"], 
	[name:"p40", index:40, mode:"zwave", size:2, type:"number", default:200, min:0, max:65535, title:"Intensity report threshold (lux)"], 
	[name:"p42", index:42, mode:"zwave", size:2, type:"number", default:0, min:0, max:65535, title:"Intensity report interval (seconds)"], 
	[name:"p60", index:60, mode:"zwave", size:1, type:"number", default:10, min:0, max:255, title:"Temperature report threshold (0.1C)"], 
	[name:"p62", index:62, mode:"zwave", size:2, type:"number", default:900, min:0, max:65535, title:"Temperature measurement interval (seconds)"], 
	[name:"p64", index:64, mode:"zwave", size:2, type:"number", default:0, min:0, max:65535, title:"Temperature report interval (seconds)"], 
	[name:"p66", index:66, mode:"zwave", size:2, type:"number", default:0, min:-100, max:100, title:"Temperature offset (0.1C)"], 
	[name:"p89", index:89, mode:"zwave", size:1, type:"enum", default:1, min:0, max:1, title:"Visual Tamper alarm ", items:[0:"No", 1:"Yes"]],
	[name:"enableDebugging", mode:"settings", type:"bool", title:"Enable Debug Logging", default:"true"]
]}


/////////////////////////////////////////////////////
// Updated event
def updated() {
  logDebug("updated")
}

/////////////////////////////////////////////////////
// Configure event
def configure() {
	logDebug("configure")
}

/////////////////////////////////////////////////////
// Installed event
def installed() {
	logDebug("Installed")
}

/////////////////////////////////////////////////////
// Update any settings that have changed
def updateSettings()
{
	def cmds = []
	def Updating = "No"
  
	if(state.currentProperties == null)
		state.currentProperties = [:]

	if(state.currentProperties.wI != settings.wakeUpInterval) {
  	cmds << zwave.wakeUpV2.wakeUpIntervalSet(seconds:settings.wakeUpInterval, nodeid:zwaveHubNodeId)
  	cmds << zwave.wakeUpV2.wakeUpIntervalGet( )
		Updating = "Yes"
	}
	
	if(CheckAssociation(1, state.currentProperties, cmds))
		Updating = "Yes"
	if(CheckAssociation(2, state.currentProperties, cmds))
		Updating = "Yes"
	if(CheckAssociation(3, state.currentProperties, cmds))
		Updating = "Yes"
		
	if(state.FirmwareVersion == null)
    cmds << zwave.versionV1.versionGet()
	
	cmds << zwave.batteryV1.batteryGet()

	// Set the individual settings
	parameterMap().each {
		if (it.mode == "zwave"){
			if (it.type == "none") {
			  if (state.currentProperties."${it.name}" != it.default) { 
				  Updating = "Yes"
					logDebug("Setting Parameter ${it.index} to ${it.default}")
				  cmds << zwave.configurationV1.configurationSet(configurationValue: integer2Array(it.default, it.size), parameterNumber: it.index, size: it.size)
				  cmds << zwave.configurationV1.configurationGet(parameterNumber: it.index)
			  } 
			}
			else if (state.currentProperties."${it.name}" == null) {
				Updating = "Yes"
				if(settings."${it.name}" != null) {
				  log.info("Setting parameter ${it.index} to " + settings."${it.name}")
				  cmds << zwave.configurationV1.configurationSet(configurationValue: integer2Array(settings."${it.name}", it.size), parameterNumber: it.index, size: it.size)
				}
        else if(it.default != null) {
				  log.info("Setting parameter ${it.index} to ${it.default}")
				  cmds << zwave.configurationV1.configurationSet(configurationValue: integer2Array(it.default, it.size), parameterNumber: it.index, size: it.size)
        }
				cmds << zwave.configurationV1.configurationGet(parameterNumber: it.index)
			}
			else if (settings."${it.name}" != null && state.currentProperties."${it.name}" != settings."${it.name}".toInteger()) { 
				Updating = "Yes"
				log.info("Setting parameter ${it.index} to " + settings."${it.name}" + " last value " + state.currentProperties."${it.name}")
				cmds << zwave.configurationV1.configurationSet(configurationValue: integer2Array(settings."${it.name}", it.size), parameterNumber: it.index, size: it.size)
				cmds << zwave.configurationV1.configurationGet(parameterNumber: it.index)
			} 
		}
	}
  sendEvent(name:"Updating", value: Updating, displayed:false, isStateChange: true)
	return cmds
}

/////////////////////////////////////////////////////
// Check if all up to date
def SettingsPending(currentProperties)
{
  def Pending = 0
	
	parameterMap().each {
		if (it.mode == "zwave"){
			if (currentProperties."${it.name}" == null)
			  Pending = Pending + 1
			else if (it.type == "none" && currentProperties."${it.name}" != it.default)
			  Pending = Pending + 1
			else if (it.type != "none" && settings."${it.name}" != null && currentProperties."${it.name}" != settings."${it.name}".toInteger())
			  Pending = Pending + 1
		}
	}
	if(currentProperties.wI != settings.wakeUpInterval)
	  Pending = Pending + 1
	if(currentProperties.a1 != zwaveHubNodeId)
	  Pending = Pending + 1
	if(currentProperties.a2 != zwaveHubNodeId)
	  Pending = Pending + 1
	if(currentProperties.a3 != zwaveHubNodeId)
	  Pending = Pending + 1
	return Pending
}

/////////////////////////////////////////////////////
// Standard Version1 VersionReport
def zwaveEvent(hubitat.zwave.commands.versionv1.VersionReport cmd) {	
  logDebug("versionv1.VersionReport '${cmd}'")
  state.FirmwareVersion = "${cmd.applicationVersion}.${cmd.applicationSubVersion}"
  state.ZWaveProtocolVersion = "${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
}

/////////////////////////////////////////////////////
// basicv1.BasicSet
def zwaveEvent(hubitat.zwave.commands.basicv1.BasicSet cmd) {
	def motion
	
	motion = (cmd.value) ? "active" : "inactive"
	if(device.currentValue("motion") != motion)
	{
    log.info("motion '${motion}'")
	  sendEvent(name: "motion", value: motion)
	}
}

/////////////////////////////////////////////////////
// sensorbinaryv2.SensorBinaryReport
def zwaveEvent(hubitat.zwave.commands.sensorbinaryv2.SensorBinaryReport cmd) {
	logDebug "sensorbinaryv2.SensorBinaryReport $cmd"
}

/////////////////////////////////////////////////////
// sensormultilevelv5.SensorMultilevelReport
def zwaveEvent(hubitat.zwave.commands.sensormultilevelv5.SensorMultilevelReport cmd) {
	logDebug("sensormultilevelv5.SensorMultilevelReport ${cmd}")
	
	switch (cmd.sensorType as Integer) {
	case 1:
		def cmdScale = cmd.scale == 1 ? "F" : "C"
		sendEvent(name: "temperature", unit: getTemperatureScale(), value: convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision), displayed: true)
	  log.info "Temperature ${cmd.scaledSensorValue}C"
		break
	case 3:
		sendEvent(name: "illuminance", value: cmd.scaledSensorValue.toInteger().toString(), unit:"lux", displayed: true)
	  log.info "Illuminance ${cmd.scaledSensorValue}lux"
		break
	case [25,52,53,54]:
		motionEvent(cmd.sensorType, cmd.scaledSensorValue )
		break
	}
}

/////////////////////////////////////////////////////
// sensormultilevelv1.SensorMultilevelReport
def zwaveEvent(hubitat.zwave.commands.sensormultilevelv1.SensorMultilevelReport cmd) {
	logDebug("sensormultilevelv1.SensorMultilevelReport ${cmd}")
	
	switch (cmd.sensorType as Integer) {
		case 1:
			def cmdScale = cmd.scale == 1 ? "F" : "C"
			sendEvent(name: "temperature", unit: getTemperatureScale(), value: convertTemperatureIfNeeded(cmd.scaledSensorValue, cmdScale, cmd.precision), displayed: true)
		  log.info "Temperature ${cmd.scaledSensorValue}C"
			break
		case 3:
			sendEvent(name: "illuminance", value: cmd.scaledSensorValue.toInteger().toString(), unit:"lux", displayed: true)
		  log.info "Illuminance ${cmd.scaledSensorValue}lux"
			break
		case [25,52,53,54]:
			motionEvent(cmd.sensorType, cmd.scaledSensorValue )
			break
	}
}


private motionEvent(Integer sensorType, value) {
	logDebug("${device.displayName} - Executing motionEvent() with parameters: ${sensorType}, ${value}")
	def axisMap = [52: "yAxis", 53: "zAxis", 54: "xAxis"]
	switch (sensorType) {
		case 25:
			sendEvent(name: "motionText", value: "Vibration:\n${value}", displayed: false)
			break
		case 52..54:
			sendEvent(name: axisMap[sensorType], value: value , displayed: false)
			runIn(2,"axisEvent")
			break
	}
	
}


def zwaveEvent(hubitat.zwave.commands.sensoralarmv1.SensorAlarmReport cmd) {
  logDebug("sensoralarmv1.SensorAlarmReport '${cmd}'")
}

////////////////////////////////
// Standard battery report
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
	log.info "Battery ${cmd.batteryLevel}%"
  createEvent(name:"battery", value: cmd.batteryLevel, unit:"%", isStateChange:true, displayed:true)
}


/////////////////////////////////////////////////////
// Standard parse to command classes
def parse(String description) {
  def cmd = zwave.parse(description)
  if (cmd) {
    logDebug("Parsed '${description}'")
    return zwaveEvent(cmd)
  }
  logDebug("Failed to parse '${description}'")
}

/////////////////////////////////////////////////////
// Standard catch all
def zwaveEvent(hubitat.zwave.Command cmd) {
  logDebug("Unhandled event $cmd")
}

/////////////////////////////////////////////////////
// securityv1.SecurityMessageEncapsulation
def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
  logDebug("securityv1.SecurityMessageEncapsulation '${cmd}'")
	def encapsulatedCommand = cmd.encapsulatedCommand( )
	if (encapsulatedCommand)
		return zwaveEvent(encapsulatedCommand)
	else
		log.warn "Failed to extract secure message from ${cmd}"
}

/////////////////////////////////////////////////////
// crc16encapv1.Crc16Encap
def zwaveEvent(hubitat.zwave.commands.crc16encapv1.Crc16Encap cmd) {
	def encapsulatedCommand = zwave.getCommand(cmd.commandClass, cmd.command, cmd.data)
	if (encapsulatedCommand)
		zwaveEvent(encapsulatedCommand)
	else
		log.warn "Unable to extract CRC16 command from ${cmd}"
}

/////////////////////////////////////////////////////
// multichannelv3.MultiChannelCmdEncap
def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
	def encapsulatedCommand = cmd.encapsulatedCommand( )
	if (encapsulatedCommand) {
    logDebug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
		zwaveEvent(encapsulatedCommand, cmd.sourceEndPoint as Integer)
	} else
		log.warn "Could not extract multi channel command from ${cmd}"
}

/////////////////////////////////////////////////////
// Standard wakeupv1 WakeUpNotification
def zwaveEvent(hubitat.zwave.commands.wakeupv1.WakeUpNotification cmd) {
 	log.info "Device woke up"
	
	def cmds = updateSettings()
	cmds << zwave.wakeUpV1.wakeUpNoMoreInformation()
  return response(commands(cmds))
}

/////////////////////////////////////////////////////
// Standard wakeupv2 WakeUpNotification
def zwaveEvent(hubitat.zwave.commands.wakeupv2.WakeUpNotification cmd) {
 	log.info "Device woke up"
	
	def cmds = updateSettings()
	cmds << zwave.wakeUpV2.wakeUpNoMoreInformation()
  return response(commands(cmds))
}


/////////////////////////////////////////////////////
// Command sending routines
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
// create a delay between commands
private commands(commands, delay=500) {
	delayBetween(commands.collect{command(it)}, delay)
}

/////////////////////////////////////////////////////
// Format the command according to the security
private command(hubitat.zwave.Command cmd) {
	if (state.sec)
		zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
	else
		cmd.format()
}

/////////////////////////////////////////////////////
// format a message for an endpoint
private endpoint(hubitat.zwave.Command cmd, endpoint) {
  zwave.multiChannelV3.multiChannelCmdEncap(destinationEndPoint:endpoint).encapsulate(cmd)
}


/////////////////////////////////////////////////////
// Common Routines
/////////////////////////////////////////////////////

/////////////////////////////////////////////////////
// Standard debug logging
private def logDebug(message) {
  if(settings.enableDebugging == true)
	  log.debug "$message"
}

/////////////////////////////////////////////////////
// Scale temperature for units
def temperature(value, units) {
	if (location.temperatureScale != units) {
    if (location.temperatureScale == "F")
      value = value * 1.8 + 32
    else
      value = (value - 32) / 1.8
  }
  return value
}


/////////////////////////////////////////////////////
// Configuration Routines
/////////////////////////////////////////////////////


/////////////////////////////////////////////////////
// Standard config v2 report
/////////////////////////////////////////////////////
def zwaveEvent(hubitat.zwave.commands.configurationv2.ConfigurationReport cmd) {
	logDebug("configurationv2.ConfigurationReport $cmd")
	updateProperty(cmd)
}


/////////////////////////////////////////////////////
// Create the preferences from the XML
def updateProperty(cmd)
{
	state.currentProperties."p${cmd.parameterNumber}" = array2Integer(cmd.configurationValue)
	settings = SettingsPending(state.currentProperties)
	if(settings == 0) {
	  log.info("parameter ${cmd.parameterNumber} reported value ${array2Integer(cmd.configurationValue)}. All parameters updated")
	  sendEvent(name:"Updating", value:"No", displayed:false, isStateChange: true)
  }
	else
	  log.info("parameter ${cmd.parameterNumber} reported value ${array2Integer(cmd.configurationValue)}. ${settings} setting(s) left")
}


/////////////////////////////////////////////////////
// associationv2.AssociationReport
def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
	logDebug("Association for Group ${cmd.groupingIdentifier} = ${cmd.nodeId[0]}")
	
	state.currentProperties."a${cmd.groupingIdentifier}" = cmd.nodeId[0]
	settings = SettingsPending(state.currentProperties)
	if(settings == 0) {
		log.info "Association Group ${cmd.groupingIdentifier} reported node ${cmd.nodeId[0]}. All parameters updated"
	  sendEvent(name:"Updating", value:"No", displayed:false, isStateChange: true)
	}
	else
		log.info "Association Group ${cmd.groupingIdentifier} reported node ${cmd.nodeId[0]}. ${settings} setting(s) left"
}

////////////////////////////////
// wakeUpV2.WakeUpIntervalReport
def zwaveEvent(hubitat.zwave.commands.wakeupv2.WakeUpIntervalReport cmd) {
	logDebug "Wake up interval = ${cmd}"
  
	if(state.currentProperties == null)
		state.currentProperties = [:]
	state.currentProperties.wI = cmd.seconds
  
	settings = SettingsPending(state.currentProperties)
	if(settings == 0)
	  sendEvent(name:"Updating", value:"No", displayed:false, isStateChange: true)
	else
		log.info "Wake up interval reported ${cmd.seconds}S. ${settings} setting(s) left"
}

/////////////////////////////////////////////////////
// CheckAssociation
def CheckAssociation(group, currentProperties, cmds) {
	
	if(currentProperties."a${group}" != zwaveHubNodeId) {
		log.info("Updating association group ${group}")
    cmds << zwave.associationV2.associationSet(groupingIdentifier: group, nodeId: [zwaveHubNodeId])
    cmds << zwave.associationV2.associationGet(groupingIdentifier: group)
		return true
	}
	return false
}

/////////////////////////////////////////////////////
// Array to integer
def array2Integer(array) { 
	switch(array.size()) {
	case 1:
		array[0]
		break
	case 2:
		((array[0] & 0xFF) << 8) | (array[1] & 0xFF)
		break
	case 4:
		((array[0] & 0xFF) << 24) | ((array[1] & 0xFF) << 16) | ((array[2] & 0xFF) << 8) | (array[3] & 0xFF)
		break
	}
}


/////////////////////////////////////////////////////
// Integer to Array
def integer2Array(value, size) {
	
	if(value instanceof String) {
    value = value.toInteger()
	}
	switch(size) {
	case 1:
		[value & 0xFF]
    break
	case 2:
		[(value >> 8) & 0xFF, value & 0xFF]
		break
	case 4:
		[(value >> 24) & 0xFF, (value >> 16) & 0xFF, (value >> 8) & 0xFF, value & 0xFF]
		break
	}
}

Ah, I see. You're right, the versions I have do not support zwave plus so must be V1. I didn't know there was a difference until now! I'll give your driver a go, thanks very much for your help. My driver coding skills are non existent at the moment, but I'm learning by the day :slight_smile:

@entire,

So after a little patience one of my sensors is now reporting lux and motion absolutely fine with the driver you posted. No luck with the others sensors yet, but i guess its a waiting game. You're right; waking the sensors manually does nothing with this driver.

I now just need to tweak the threshold for reporting light level changes, and then work that into my rule to only put the lights on when motion is detected and light levels are low.

Thanks very much for your help!

Glad you have manged to get at least one working, hopefully the others will when they wake up.
When you press the button inside they just send a lux and temperature report and not a wake up message, i did try updating on those messages but that just failed, so left it on the wake up message.
I'm still learning so maybe there is a way of keeping them awake after those messages and sending any updates but i didn't find a reliable way.

Sorry to revive an old thread but I'm having the same trouble.

I have two FGMS-001 but they behave differently.

The illuminance values for the 'Kitchen' sensor only get updated on a configure as far as I can tell. Motion etc works as expected. I also see that 3 parameter updates are always pending. Using the 'Basic ZWAVE tool' driver I can see that the available parameters are not the same between devices, nor the reported param sizes.

I'm giving the driver you posted above a go but was suprised to see that a manual device wakeup doesn't trigger a configure.

@bobbyD can the 'Fibaro motion sensor ZW5' driver be updated to fully support all versions of this device?

B.R.