Tesla Wall Connector Status (Gen 3 with Wi-Fi) (Amps, Voltage, health, and contact sensor - "is my car plugged in")

Hubitat Tesla owners.

For folks with a Tesla Charger.... this driver checks to see if your Tesla is plugged in by directly interrogating the wall charger - Super simple...

Have a great day!

/**
 *  Tesla Plug
 *
 *  Copyright 2022 Paul Nielsen
 *
 *  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.
 *
 *  Change History:
 *
 *    Date        Who             Info            Version
 *    ----        ---             ----            -------
 *    2022-09-13  Paul Nielsen    Created         0.0
 * 
 */
import groovy.json.JsonSlurper

metadata {
    definition (name: "Tesla Plug", namespace: "PMFN", author: "Paul Nielsen") {
        capability "Sensor"
        capability "Contact Sensor"
        command "refresh"
        
        attribute 'voltage', 'number'
        attribute 'current', 'number'
        attribute 'status', 'string'
    }

    preferences {
        input(name: "deviceIP", type: "string", title:"Device IP Address", description: "Enter IP Address of your Tesla Home Charger", required: true, displayDuringSetup: true)
    }
}

def initialize() {
    runEvery1Minute('refresh')
    
}

def parse(String description) {
    log.debug(description)
    def msg = parseLanMessage(description)   
    def bodyString = new groovy.json.JsonSlurper().parseText(msg.body)
    //log.debug(bodyString)
    def volts = bodyString.'grid_v'
    def amps = bodyString.'vehicle_current_a'
    sendEvent(name: "voltage", value: volts)
    sendEvent(name: "current", value: amps)
    log.debug(bodyString.'vehicle_connected')
    if (bodyString.'vehicle_connected') {
        close() 
    } else {
        open()
    }
    

}

def refresh() {
    getCmd()
}

def open(){
	sendEvent(name: "contact", value: "open")
}

def close(){
	sendEvent(name: "contact", value: "closed")
}

def getCmd() {
    def localDevicePort = "80"
    def path = "/api/1/vitals" 
    def body = ""
    def method = "GET"
    def deviceContent = "application/json"
    //if(deviceBody) body = deviceBody
    def headers = [:] 
    headers.put("HOST", "${deviceIP}:${localDevicePort}")
    headers.put("Content-Type", deviceContent)

    try {
        def hubAction = new hubitat.device.HubAction(
            method: method,
            path: path,
            body: body,
            headers: headers
            )
        //log.debug hubAction
        sendEvent(name: "status", value: "healthy")
        return hubAction
    }
    catch (Exception e) {
        log.debug "getCmd exception ${e} on ${hubAction}"
        sendEvent(name: "status", value: "unhealthy")
    }  
}
5 Likes

Link?

Sorry... I'm trying to figure that out. Forgot how to post code.

If you want to post the code directly here, use the </> pre-formatted text button.

So that the code will show up like this.

/**
 *  Tesla Plug
 *
 *  Copyright 2022 Paul Nielsen
 *
 *  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.
 *
 *  Change History:
 *
 *    Date        Who             Info            Version
 *    ----        ---             ----            -------
 *    2022-09-13  Paul Nielsen    Created         0.0
 * 
 */
import groovy.json.JsonSlurper

metadata {
    definition (name: "Tesla Plug", namespace: "PMFN", author: "Paul Nielsen") {
        capability "Sensor"
        capability "Contact Sensor"
        command "refresh"
        
        attribute 'voltage', 'number'
        attribute 'current', 'number'
        attribute 'status', 'string'
    }

    preferences {
        input(name: "deviceIP", type: "string", title:"Device IP Address", description: "Enter IP Address of your Tesla Home Charger", required: true, displayDuringSetup: true)
    }
}

def initialize() {
    runEvery1Minute('refresh')
    
}

def parse(String description) {
    log.debug(description)
    def msg = parseLanMessage(description)   
    def bodyString = new groovy.json.JsonSlurper().parseText(msg.body)
    //log.debug(bodyString)
    def volts = bodyString.'grid_v'
    def amps = bodyString.'vehicle_current_a'
    sendEvent(name: "voltage", value: volts)
    sendEvent(name: "current", value: amps)
    log.debug(bodyString.'vehicle_connected')
    if (bodyString.'vehicle_connected') {
        close() 
    } else {
        open()
    }
    

}

def refresh() {
    getCmd()
}

def open(){
	sendEvent(name: "contact", value: "open")
}

def close(){
	sendEvent(name: "contact", value: "closed")
}

def getCmd() {
    def localDevicePort = "80"
    def path = "/api/1/vitals" 
    def body = ""
    def method = "GET"
    def deviceContent = "application/json"
    //if(deviceBody) body = deviceBody
    def headers = [:] 
    headers.put("HOST", "${deviceIP}:${localDevicePort}")
    headers.put("Content-Type", deviceContent)

    try {
        def hubAction = new hubitat.device.HubAction(
            method: method,
            path: path,
            body: body,
            headers: headers
            )
        //log.debug hubAction
        sendEvent(name: "status", value: "healthy")
        return hubAction
    }
    catch (Exception e) {
        log.debug "getCmd exception ${e} on ${hubAction}"
        sendEvent(name: "status", value: "unhealthy")
    }  
}
2 Likes

Thank you

1 Like

Nice, that's pretty neat. For me personally electric vehicles appear to be much worse for the environment. I read it takes 100-300 barrels of oil to fully produce a complete battery assembly for a Tesla. Car looks to be tremendous fun to drive, however if you're in Cali, people are being asked to not charge their cars, how the hell do you get to work?

Solar panels -> Free “fuel”!

We charge our EV once a week, so it wouldn’t be much of an issue for us, but that said, we don’t have much traffic to deal with here.

Electric is great for slow or stop and go traffic - doesn’t use much electricity while stopped, compared to gas cars!

2 Likes

Hi @nielsen411 . Thanks for doing this. I added a couple of lines to get the last charge session in Wh.
def last = bodyString.'session_energy_wh'
sendEvent(name: "last charge", value: last + ' Wh')

Nice. Thank you. I will add that to the next version.

You can also do some math on it and display Kwh.
def last = (bodyString.'session_energy_wh')/1000
sendEvent(name: "last charge", value: last + ' Kwh')

It would be great if there was some way to turn the charging on and off.

Version 1.0. Thanks @Wounded

/**
 *  Tesla Plug
 *
 *  Copyright 2022 Paul Nielsen
 *
 *  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.
 *
 *  Change History:
 *
 *    Date        Who             Info            Version        Notes:
 *    ----        ---             ----            -------        ------
 *    2022-09-13  Paul Nielsen    Created         0.0            
 *    2022-09-16  Paul Nielsen    Update          1.0            Added new Fields (Thanks @wounded) and debug toggle
 *
 */
import groovy.json.JsonSlurper

metadata {
    definition (name: "Tesla Plug", namespace: "PMFN", author: "Paul Nielsen") {
        capability "Sensor"
        capability "Contact Sensor"
        command "refresh"
        
        attribute 'voltage', 'number'
        attribute 'current', 'number'
        attribute 'status', 'string'
        attribute 'last_charge', 'string'
        attribute 'charge_status', 'string'
    }

    preferences {
        input(name: "deviceIP", type: "string", title:"Device IP Address", description: "Enter IP Address of your Tesla Home Charger", required: true, displayDuringSetup: true)
        input name: 'loggingEnabled', type: 'bool', title: '<b>Enable Logging?</b>', description: '<div><i>Automatically disables after 30 minutes.</i></div><br>', defaultValue: false
    }
}

def initialize() {
    runEvery1Minute('refresh')
    if (settings.loggingEnabled) runIn(1800, disableLogging)

}

def parse(String description) {
    logDebug "Debug: JSON Message: '${description}'"
    def msg = parseLanMessage(description)   
    def bodyString = new groovy.json.JsonSlurper().parseText(msg.body)
    //log.debug(bodyString)
    def volts = bodyString.'grid_v'
    def amps = bodyString.'vehicle_current_a'
    def last = bodyString.'session_energy_wh'/1000
    def chargeStatus = bodyString.'evse_state'
    def chargeStatus2
    switch(chargeStatus){
    case 1 : chargeStatus2 = "Not Connected";
        break;
    case 4 : chargeStatus2 = "Finished";
        break;
    case 11 : chargeStatus2 = "Charging";
        break;
    default: chargeStatus2 = "Unknown"
    }
    sendEvent(name: "charge_status", value: chargeStatus2)
    sendEvent(name: "last_charge", value: last + ' KWh')
    sendEvent(name: "voltage", value: volts)
    sendEvent(name: "current", value: amps)
    logDebug "Debug: charge status: '${chargeStatus2}'"
    if (bodyString.'vehicle_connected') {
        close() 
    } else {
        open()
    }
    

}

def refresh() {
    getCmd()
}

def open(){
	sendEvent(name: "contact", value: "open")
}

def close(){
	sendEvent(name: "contact", value: "closed")
}

def getCmd() {
    def localDevicePort = "80"
    def path = "/api/1/vitals" 
    def body = ""
    def method = "GET"
    def deviceContent = "application/json"
    def headers = [:] 
    headers.put("HOST", "${deviceIP}:${localDevicePort}")
    headers.put("Content-Type", deviceContent)

    try {
        def hubAction = new hubitat.device.HubAction(
            method: method,
            path: path,
            body: body,
            headers: headers
            )
        logDebug "Debug: hubAction '${hubAction}'"
        sendEvent(name: "status", value: "healthy")
        return hubAction
    }
    catch (Exception e) {
        logDebug "Debug: getCmd exception '${e}' on '${hubAction}'"
        sendEvent(name: "status", value: "unhealthy")
    }  
}

void disableLogging() {
	log.info 'Logging disabled'
	device.updateSetting('loggingEnabled',[value:'false',type:'bool'])
}

void logDebug(str) {
    if (loggingEnabled) {
        log.debug str
    }
}

Thank you for this @nielsen411
On line 65 there's an additional evse_state of 9 = "Charging Stopped". I've seen this state returned when the Wall Charger is plugged in and waiting to be charged (ex: when not charging during peak-hours, waiting to start by departure time, or just before/after a "Finished" state).

    case 9 : chargeStatus2 = "Charging Stopped";
        break;

Keep up the great work. Thanks again!

I tried to paste the code as an "App Code" which gave me a warning that it might contain driver code. Error code reads: Metadata Error:Please check if you inadvertently pasted driver code into apps code window on line 25

I did not get any issues with pasting into as Driver Code instead and successfully saved.

you can also use the tesla car app. that can tell you if the car is plugged in..

ie..

Hi. This is a device driver. Install the driver code, add a new virtual device (the name of this driver), open the device, and set the IP... you should be good to go after that...