Am I the only one with Simplisafe integration stopped working today, the logs show connection reset when trying to login? Are we losing Simplisafe integration after Blink as well. While I do realize this was always a risk, it sucks that all companies are trying to close their systems.
Looks like I am having issues too. Here is what I see in the Live Logging:
11:57:04 AM: error java.net.SocketException: Connection reset
11:57:04 AM: info Executing 'loginā
11:57:04 AM: debug Need to login
11:57:04 AM: debug No state.auth
11:57:04 AM: info Executing 'apiā
11:57:04 AM: info Executing 'statusā
11:57:04 AM: info Executing āpollā
8:55:10 AM: error java.net.SocketException: Connection reset
8:55:10 AM: info Executing 'loginā
8:55:10 AM: debug Need to login
8:55:10 AM: debug No state.auth
8:55:10 AM: info Executing 'apiā
8:55:10 AM: info Executing āawayā
I tried deleting everything and reinstalling. hrmph
Manā¦this is a real bummer, I had things setup and working perfectly.
I am also seeing this as well. My guess is that something has changed now
that they switched to their new online control panel.
This was first reported for people with the new v3 system but now it
appears to be more wide spread.
I have a v3 unit on the way so I can take a look at the changes and update
the device handler.
Really great to hear that you are still supporting this device handler! Just wanted to say thanks
My system was still working as of this morningā¦ iāll be tragic to loose this feature. Literally a criteria when i bought into both ST and SS.
My alarm set correctly around 6:30 AM PST.
This hasnāt updated since last night for me.
Joel_Day, can you tell me where you got the from. I can get to that point, but donāt know what that is.
I did some web tracing when I logged into the new SS portal. Thatās where I found the API endpoints.
Do you have a specific question?
Hey @Joel_Day,
Iām trying to work on a fix for this, but Iām not able to use the grant_type you discovered. Is it still working for you?
{
"error": "unsupported_grant_type",
"error_description": "Unsupported grant type: undefined"
}
Like I posted earlier, after upgrading to SS3, I couldnāt use the device handler for the newer SS3 device. It looks like we need to use the new API as Joel_Day figured out. I took a stab at updating the device handler and with some of the code from tobycth3ās device handler and I got it working with my SS3. See the code below. I
needed only the arm/disarm functionality so I have updated the code to do only that part.
This is my first attempt at custom device handlers and Iām not a good programmer but I can tell you that this is working for me
preferences {
input(name: "username", type: "text", title: "Username", required: "true", description: "SimpliSafe Username")
input(name: "password", type: "password", title: "Password", required: "true", description: "SimpliSafe Password")
}
metadata {
definition (name: "SimpliSafe 3", namespace: "SimpliSafe3", author: "Multiple Authors") {
capability "Alarm"
command "home"
command "away"
command "off"
command "update_state"
}
tiles(scale: 2) {
multiAttributeTile(name:"alarm", type: "generic", width: 6, height: 4){
tileAttribute ("device.alarm", key: "PRIMARY_CONTROL") {
attributeState "off", label:'${name}', icon: "st.security.alarm.off", backgroundColor: "#594531"
attributeState "home", label:'${name}', icon: "st.Home.home4", backgroundColor: "#00BEAC"
attributeState "away", label:'${name}', icon: "st.security.alarm.on", backgroundColor: "#008CC1"
attributeState "pending off", label:'${name}', icon: "st.security.alarm.off", backgroundColor: "#ffffff"
attributeState "pending away", label:'${name}', icon: "st.Home.home4", backgroundColor: "#ffffff"
attributeState "pending home", label:'${name}', icon: "st.security.alarm.on", backgroundColor: "#ffffff"
attributeState "failed set", label:'error', icon: "st.secondary.refresh", backgroundColor: "#d44556"
}
tileAttribute("device.events", key: "SECONDARY_CONTROL", wordWrap: true) {
attributeState("default", label:'${currentValue}')
}
}
standardTile("off", "device.alarm", width: 2, height: 2, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
state ("off", label:"off", action:"off", icon: "st.security.alarm.off", backgroundColor: "#594531", nextState: "pending")
state ("away", label:"off", action:"off", icon: "st.security.alarm.off", backgroundColor: "#505050", nextState: "pending")
state ("home", label:"off", action:"off", icon: "st.security.alarm.off", backgroundColor: "#505050", nextState: "pending")
state ("pending", label:"pending", icon: "st.security.alarm.off", backgroundColor: "#ffffff")
}
standardTile("away", "device.alarm", width: 2, height: 2, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
state ("off", label:"away", action:"away", icon: "st.security.alarm.on", backgroundColor: "#505050", nextState: "pending")
state ("away", label:"away", action:"away", icon: "st.security.alarm.on", backgroundColor: "#008CC1", nextState: "pending")
state ("home", label:"away", action:"away", icon: "st.security.alarm.on", backgroundColor: "#505050", nextState: "pending")
state ("pending", label:"pending", icon: "st.security.alarm.on", backgroundColor: "#ffffff")
}
standardTile("home", "device.alarm", width: 2, height: 2, canChangeIcon: false, inactiveLabel: true, canChangeBackground: false) {
state ("off", label:"home", action:"home", icon: "st.Home.home4", backgroundColor: "#505050", nextState: "pending")
state ("away", label:"home", action:"home", icon: "st.Home.home4", backgroundColor: "#505050", nextState: "pending")
state ("home", label:"home", action:"home", icon: "st.Home.home4", backgroundColor: "#00BEAC", nextState: "pending")
state ("pending", label:"pending", icon: "st.Home.home4", backgroundColor: "#ffffff")
}
standardTile("refresh", "device.alarm", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
state "default", action:"update_state", icon:"st.secondary.refresh"
}
main(["alarm"])
details(["alarm","off", "away", "home", "refresh"])
}
}
def installed() {
init()
}
def updated() {
unschedule()
init()
}
def init() {
runEvery5Minutes(poll)
}
// handle commands
def off() {
log.info "Setting SimpliSafe mode to 'Off'"
setState ('off')
poll()
}
def home() {
log.info "Setting SimpliSafe mode to 'Home'"
setState ('home')
poll()
}
def away() {
log.info "Setting SimpliSafe mode to 'Away'"
setState ('away')
poll()
}
def update_state() {
log.info "Refreshing SimpliSafe state..."
poll()
}
def setState (alState){
if (now() > state.tokenExpiry)
{
apiLogin()
}
if (alState == "off")
{
httpPost([ uri: getAPIUrl("alarmOff"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8" ])
}
else if (alState == "home")
{
httpPost([ uri: getAPIUrl("alarmHome"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8" ])
}
else if (alState == "away")
{
httpPost([ uri: getAPIUrl("alarmAway"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8" ])
}
else
{
log.info "Invalid state requested."
}
}
def poll() {
log.info "Executing polling..."
if (now() > state.tokenExpiry)
{
apiLogin()
}
httpGet ([uri: getAPIUrl("refresh"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8"]) { response ->
sendEvent(name: "alarm", value: response.data.state)
}
//apiLogout()
}
def apiLogin() {
log.info "Getting authrorization token..."
//get token
def authBody = [ "grant_type":"password",
"username":settings.username,
"password": settings.password ]
def authHeader = [ "Authorization":"Basic NGRmNTU2MjctNDZiMi00ZTJjLTg2NmItMTUyMWIzOTVkZWQyLjEtMC0wLldlYkFwcC5zaW1wbGlzYWZlLmNvbTo=" ]
httpPost([ uri: getAPIUrl("initAuth"), headers: authHeader, contentType: "application/json; charset=utf-8", body: authBody ]) { response ->
state.token = response.data.access_token
state.tokenType = response.data.token_type
state.respAuthHeader = ["Authorization":state.tokenType + " " + state.token]
state.tokenExpiry = now() + 3600000
}
if (!state.uid)
{
getUserId()
}
if (!state.subscriptionId)
{
getSubscriptionId()
}
}
def getUserId() {
//check auth and get uid
httpGet ([uri: getAPIUrl("authCheck"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8"]) { response ->
state.uid = response.data.userId
}
}
def getSubscriptionId() {
//get subscription id
httpGet ([uri: getAPIUrl("subId"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8"]) { response ->
String tsid = response.data.subscriptions.location.sid
state.subscriptionId = tsid.substring(1, tsid.length() - 1)
}
}
def checkAuth()
{
//check auth and return status
httpGet ([uri: getAPIUrl("authCheck"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8"]) { response ->
return response.status
}
}
def apiLogout() {
httpDelete([ uri: getAPIUrl("initAuth"), headers: state.respAuthHeader, contentType: "application/json; charset=utf-8" ]) { response ->
if (response.status == 200) {
state.subscriptionId = null
log.info "Logged out from API."
}
}
}
def getTime()
{
def tDate = new Date()
return tDate.getTime()
}
def getAPIUrl(urlType) {
if (urlType == "initAuth")
{
return "https://api.simplisafe.com/v1/api/token"
}
else if (urlType == "authCheck")
{
return "https://api.simplisafe.com/v1/api/authCheck"
}
else if (urlType == "subId" )
{
return "https://api.simplisafe.com/v1/users/$state.uid/subscriptions?activeOnly=false"
}
else if (urlType == "alarmOff" )
{
return "https://api.simplisafe.com/v1/ss3/subscriptions/$state.subscriptionId/state/off"
}
else if (urlType == "alarmHome" )
{
return "https://api.simplisafe.com/v1/ss3/subscriptions/$state.subscriptionId/state/home"
}
else if (urlType == "alarmAway" )
{
return "https://api.simplisafe.com/v1/ss3/subscriptions/$state.subscriptionId/state/away"
}
else if (urlType == "refresh")
{
return "https://api.simplisafe.com/v1/ss3/subscriptions/$state.subscriptionId/state"
}
else
{
log.info "Invalid URL type"
}
}
For some reason I didnāt paste what I was asking. What I meant was where did the SUBSCRIPTION-ID come from.
I can get all the way to the following point, and donāt know what to use for that value.
$settings = Invoke-WebRequest -Uri "https://api.simplisafe.com/v1/subscriptions/<SUBSCRIPTION-ID>/settings?cached=true&settingsType=sensors" -WebSession $ssLogin -Headers $headers
I was able to do it earlier and could do the grant_type password. Here is what mine looked like.
{
"grant_type": "password",
"username": "YourEmail@email.com",
"password": "YourPassword123"
}
You can get the userId with this request.
$authCheck = Invoke-WebRequest -Uri āhttps://api.simplisafe.com/v1/api/authCheckā -WebSession $ssLogin -Headers $headers
use that userId in this URL and do a get to see the subscription id.
āhttps://api.simplisafe.com/v1/users//subscriptions?activeOnly=falseā
"https://api.simplisafe.com/v1/users/<UserId>/subscriptions?activeOnly=false"
@RCP
Thanks for putting this together. I attempted to use it on my v2 SimpliSafe but it kept throwing errors when requesting a token. Iām starting to wonder if we are going to need separate handlers for v2/v3.
Iām going to try and spend a little time on this tonight to see if I can come up with a fix for v2 users.
I was able to do it through a separate client app doing post and get with my SS2. I will try this version later.