Visonic - MCT-340 E --Some Do Some Don't

I am switching from Smarthings and I have about 15 of these. Some of them work and some of them don't. Some will work for a day or two and then they stop. What is weird the contact portion works on some but the temp does not. Some show 32 degrees, some 77, and some don't show anything. Is there a more reliable driver for these that is not the generic?

Also in pairing, I could be sitting right next to the hub and some pair, some don't and some pair as device. Something ain't right here

What driver were you using on SmartThings?

Before doing anything else, be sure to hit the CONFIGURE button on the device page for each of these. It almost sounds like the driver didn't get completely configured.

1 Like

When they pair as "Device" it means the fingerprint of the device was not recognized by Hubitat in order to select the correct driver. Even if they are the same make and model, different production runs may be different enough that they have a different fingerprint. If you repeatedly see them pairing as "Device" tag Mike.Maxwell and send him a screenshot of the data panel that you see immediately after pairing - that may allow him to update the logic that recognizes the devices.

2 Likes

I used

  • Visonic Door/Window Sensor
  • Copyright 2017 Tomas Axerot
  • 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.

*/
import physicalgraph.zigbee.clusters.iaszone.ZoneStatus

metadata {
definition (name: "Visonic Door/Window Sensor", namespace: "tomasaxerot", author: "Tomas Axerot") {
capability "Battery"
capability "Configuration"
capability "Contact Sensor"
capability "Refresh"
capability "Temperature Measurement"
capability "Health Check"
capability "Sensor"

	command "enrollResponse"


	fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Visonic", model: "MCT-340 SMA"
    fingerprint inClusters: "0000,0001,0003,0402,0500,0020,0B05", outClusters: "0019", manufacturer: "Visonic", model: "MCT-340 E"
}

simulator {

}

preferences {
	input title: "Temperature Offset", description: "This feature allows you to correct any temperature variations by selecting an offset. Ex: If your sensor consistently reports a temp that's 5 degrees too warm, you'd enter \"-5\". If 3 degrees too cold, enter \"+3\".", displayDuringSetup: false, type: "paragraph", element: "paragraph"
	input "tempOffset", "number", title: "Degrees", description: "Adjust temperature by this many degrees", range: "*..*", displayDuringSetup: false
}

tiles(scale: 2) {
	multiAttributeTile(name: "contact", type: "generic", width: 6, height: 4) {
		tileAttribute("device.contact", key: "PRIMARY_CONTROL") {
			attributeState "open", label: '${name}', icon: "st.contact.contact.open", backgroundColor: "#e86d13"
			attributeState "closed", label: '${name}', icon: "st.contact.contact.closed", backgroundColor: "#00A0DC"
		}
	}

	valueTile("temperature", "device.temperature", inactiveLabel: false, width: 2, height: 2) {
		state "temperature", label: '${currentValue}°',
				backgroundColors: [
						[value: 31, color: "#153591"],
						[value: 44, color: "#1e9cbb"],
						[value: 59, color: "#90d2a7"],
						[value: 74, color: "#44b621"],
						[value: 84, color: "#f1d801"],
						[value: 95, color: "#d04e00"],
						[value: 96, color: "#bc2323"]
				]
	}
	valueTile("battery", "device.battery", decoration: "flat", inactiveLabel: false, width: 2, height: 2) {
		state "battery", label: '${currentValue}% battery', unit: ""
	}

	standardTile("refresh", "device.refresh", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
		state "default", action: "refresh.refresh", icon: "st.secondary.refresh"
	}
    
    standardTile("configure", "device.configure", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
		state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
	}

	main(["contact", "temperature"])
	details(["contact", "temperature", "battery", "refresh", "configure"])
}	

}

def parse(String description) {
log.debug "description: $description"

Map map = [:]
if (description?.startsWith('catchall:')) {
	map = parseCatchAllMessage(description)
}
else if (description?.startsWith('read attr -')) {
	map = parseReportAttributeMessage(description)
}
else if (description?.startsWith('temperature: ')) {
	map = parseCustomMessage(description)
}
else if (description?.startsWith('zone status')) {
	map = parseIasMessage(description)
}

log.debug "Parse returned $map"
def result = map ? createEvent(map) : null

if (description?.startsWith('enroll request')) {
	List cmds = enrollResponse()
    log.debug "enroll response: ${cmds}"
    result = cmds?.collect { new physicalgraph.device.HubAction(it) }
}
return result

}

private Map parseCatchAllMessage(String description) {
Map resultMap = [:]
def cluster = zigbee.parse(description)
if (shouldProcessMessage(cluster)) {
switch(cluster.clusterId) {
case 0x0001:
resultMap = getBatteryResult(cluster.data.last())
break

        case 0x0402:
            log.debug 'TEMP'
            // temp is last 2 data values. reverse to swap endian
            String temp = cluster.data[-2..-1].reverse().collect { cluster.hex1(it) }.join()
            def value = getTemperature(temp)
            resultMap = getTemperatureResult(value)
            break
    }
}

return resultMap

}

private boolean shouldProcessMessage(cluster) {
// 0x0B is default response indicating message got through
// 0x07 is bind message
boolean ignoredMessage = cluster.profileId != 0x0104 ||
cluster.command == 0x0B ||
cluster.command == 0x07 ||
(cluster.data.size() > 0 && cluster.data.first() == 0x3e)
return !ignoredMessage
}

private Map parseReportAttributeMessage(String description) {
Map descMap = (description - "read attr - ").split(",").inject([:]) { map, param ->
def nameAndValue = param.split(":")
map += [(nameAndValue[0].trim()):nameAndValue[1].trim()]
}
log.debug "Desc Map: $descMap"

Map resultMap = [:]
if (descMap.cluster == "0402" && descMap.attrId == "0000") {
	def value = getTemperature(descMap.value)
	resultMap = getTemperatureResult(value)
}
else if (descMap.cluster == "0001" && descMap.attrId == "0020") {
	resultMap = getBatteryResult(Integer.parseInt(descMap.value, 16))
}

return resultMap

}

private Map parseCustomMessage(String description) {
Map resultMap = [:]
if (description?.startsWith('temperature: ')) {
def value = zigbee.parseHATemperatureValue(description, "temperature: ", getTemperatureScale())
resultMap = getTemperatureResult(value)
}
return resultMap
}

private Map parseIasMessage(String description) {
ZoneStatus zs = zigbee.parseZoneStatus(description)

return zs.isAlarm1Set() ? getContactResult('open') : getContactResult('closed')

}

def getTemperature(value) {
def celsius = Integer.parseInt(value, 16).shortValue() / 100
if(getTemperatureScale() == "C"){
return celsius
} else {
return celsiusToFahrenheit(celsius) as Integer
}
}

private Map getBatteryResult(rawValue) {
log.debug 'Battery'
def linkText = getLinkText(device)

def result = [:]

if (!(rawValue == 0 || rawValue == 255)) {
	def volts = rawValue / 10
	def minVolts = 2.1
	def maxVolts = 3.0
	def pct = (volts - minVolts) / (maxVolts - minVolts)
	def roundedPct = Math.round(pct * 100)
	result.value = Math.min(100, roundedPct)
	result.descriptionText = "${linkText} battery was ${result.value}%"
	result.name = 'battery'
}

return result

}

private Map getTemperatureResult(value) {
log.debug 'TEMP'
def linkText = getLinkText(device)
if (tempOffset) {
def offset = tempOffset as int
def v = value as int
value = v + offset
}
def descriptionText = "${linkText} was ${value}°${temperatureScale}"
return [
name: 'temperature',
value: value,
descriptionText: descriptionText,
unit: temperatureScale
]
}

private Map getContactResult(value) {
log.debug 'Contact Status'
def linkText = getLinkText(device)
def descriptionText = "${linkText} was ${value == 'open' ? 'opened' : 'closed'}"
return [
name: 'contact',
value: value,
descriptionText: descriptionText
]
}

/**

  • PING is used by Device-Watch in attempt to reach the Device
  • */
    def ping() {
    return zigbee.readAttribute(0x0402, 0x0000) // Read the Temperature Cluster
    }

def refresh()
{
log.debug "Refreshing Temperature and Battery"
def refreshCmds = [

    "st rattr 0x${device.deviceNetworkId} 1 0x402 0", "delay 200",
	"st rattr 0x${device.deviceNetworkId} 1 1 0x20"

]

return refreshCmds + enrollResponse()

}

def configure() {
// Device-Watch allows 2 check-in misses from device
sendEvent(name: "checkInterval", value: 60 * 12, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])

String zigbeeEui = swapEndianHex(device.hub.zigbeeEui)
	log.debug "Configuring Reporting, IAS CIE, and Bindings."
def enrollCmds = [
	"delay 1000",

	"zcl global write 0x500 0x10 0xf0 {${zigbeeEui}}", "delay 200",
	"send 0x${device.deviceNetworkId} 1 1", "delay 1500",

    //"raw 0x500 {01 23 00 00 00}", "delay 200",
    //"send 0x${device.deviceNetworkId} 1 1", "delay 1500",
]
return enrollCmds + zigbee.batteryConfig() + zigbee.temperatureConfig(30, 300) + refresh() // send refresh cmds as part of config

}

def enrollResponse() {
log.debug "Sending enroll response"
[

"raw 0x500 {01 23 00 00 00}", "delay 200",
"send 0x${device.deviceNetworkId} 1 1"

]

}
private hex(value) {
new BigInteger(Math.round(value).toString()).toString(16)
}

private String swapEndianHex(String hex) {
reverseArray(hex.decodeHex()).encodeHex()
}

private byte[] reverseArray(byte[] array) {
int i = 0;
int j = array.length - 1;
byte tmp;
while (j > i) {
tmp = array[j];
array[j] = array[i];
array[i] = tmp;
j--;
i++;
}
return array
}

As a side bar, in terms of hubitat drivers, generic doesnt equate to crappy, it simply means that driver generally will work with any number of spec compliant devices that dont expose any manufacturer specific features.

5 Likes

Not sure how well it works, but if you remove the tiles sections and replace physicalgraph with hubitat it will save.... if you want to try it instead of the Generic

It looks like the built-in Generic Zigbee Contact Sensor should work for this device unless there is some feature or functionality of the third-party driver that you desire.
Starting with the built-in driver has the advantage that the Hubitat folks (like Mike.Maxwell) can help with it.
You can manually select the driver from the device page for this device.


This is a screen shot from: List of Compatible Devices - Hubitat Documentation

1 Like

I have several (MCT-340E) using the in built Generic Zigbee Contact Sensor. They report battery, open/close, temp. Never had any issues. I believe @danabw has mentioned he really likes these also.

2 Likes

I have a fair number of these also, and have had no trouble with them using whatever driver HE chooses "generic contact sensor", but they are "SMA"'s. Does the "e" denote a newer version?

1 Like

I am not sure What the E denotes But I have 5 of the 15 I have sitting right here blinking and will not even pair and I could hit the hub with one of these. I must have something else going on. I deleted them out of my ST but maybe they still think they are attached?

I tried the ST driver and removed the tile section and it did not like that.

These are Zigbee so deleting them out of SmartThings likely does nothing. You have to do a reset on them before you can pair them to a new hub.

I had some issues when I moved from Smartthings once you remove them from Smartthings pull the battery, hold down on the tamper switch and put battery in and then release tamper switch, once I did that and paired them I have not had an issue and the batteries seem to last longer with Hubitat.

1 Like

The reset instructions:

https://docs.hubitat.com/index.php?title=Join_and_Reset_Instructions#Visonic

1 Like

What Paul said.

2 Likes

I mainly use MCT-350s now, but for the 340s I have around that is all I have ever done. Reset, then pair.

Well I got my old driver to install . Maybe I just need to move my hub around . After looking at my others that I got to work some of those are not working anymore. There may be something else going on.

If you need to move your hub around to pair the devices, then they likely won't work when you move the hub away again...

Zigbee devices should always be paired in place, with the hub in its normal location. If they won't pair like that, they won't work like that either.

A lot of people believe the radio/antenna combo is 'weaker' in Hubitat than ST or Wink (I say believe as I can't confirm. I have tons of repeating devices, so have never had to worry about signal range - relying instead on the mesh). You may need more zigbee repeating devices than you did before. :man_shrugging:

Thanks Eric but found that page and followed the instructions. It sits like this forever

You should include them one at a time, reset all three, then pull the batteries on the other two ect...
Include and test in place, once working then move to the next one...