{Driver} Connector Relay Hubitat Driver (DD7006 P-Box) local control

Awesome I'm glad we're making progress I've got another pair of drivers for you to test, It appears the 7002B bridge handles things a little differently than the new 7006 bridge which is why I haven't seen the same errors. I've also not come across the click close again issue (I don't use the easy dashboard and don't have the same buttons) My dashboard is below, I've got sliders to move the screens, as well as buttons to open and close both at the same time and a stop button that also refreshes the location so the hub know exactly where the screens stopped

Dashboard image

I did see in playing with the easy dashboard you can expand the tiles and a slider shows up which is pretty cool, but most of my other dashboards are full of features/modifications that aren't possible/available in Easy Dashboard yet

Give these a try they should take care of the last errors

Installed and initialized the controller. When I performed a refresh I get the same Groovy error.

I then went and refreshed each child and both were fine.

Tested using EZ dashboard and from the home page as a favorite they worked fine.
Tested using Devices tab and they do not work. Both spots they are Window Shade
Still have the same message for the Shades Controller.

Screenshot 2026-04-03 062412
Screenshot 2026-04-03 062341

In short, I am able to move both shades from the favorites screen. No movement.from the device screen. When in the controller open/close/stop are flawless. Position reports fine.

Easy Dashboard Template is Slider + Buttons. Not sure if slider is supposed to move to a set position?

I'm still not sure on your logs (my devices don't result in any errors like that, but I'm still trying to figure that out) The Shades Controller on your dashboard is your Parent device there isn't anything you can do with it from the easy dashboard (Hubitat doesn't have a Device template that will work with it) the sliders should work to set the location of the screens (these are roller screens correct) they report they are (10000000)

I see from your bottom screen shot you're using the Hubitat app's Devices page I have never really used the app that way, I just tested it out and mine works as expected click the button and it opens or closes fully and slide the button to go to a specific spot.

I know this is a pain in the neck but any way you can or would delete your existing devices and drivers, reboot the Hubitat and reinstall the drivers and setup the devices fresh.

I made some more changes to the battery calculation (my devices are Hardwired maybe that would explain why I'm not getting those errors) I rarely use the app other than to use my dashboards. I have my dashboards setup like an app (links to and from dashboards on each dashboard along with different toggles/sensor statuses etc. (only what my wife or I need tailored to each user... It's a pain to update or change but luckily that's not a regular occurrence She's happy so that's the most important part)

Removed Links to cleanup thread

I reinstalled and reloaded with no change.

So, I then decided to put Copilot to work. There were two sections of code that it wanted me to update.



Here are the updated code sections.

def updateStandardDeviceStatus(child, Map data) {
def blindTypes = getBlindTypes()
def operationTypes = getOperationTypes()
def currentStates = getCurrentStates()
def voltageModes = getVoltageModes()
def wirelessModes = getWirelessModes()

// --- POSITION ---
if (data.currentPosition != null) {
    def bridgePos = data.currentPosition as Integer
    def hubitatLevel = 100 - bridgePos

    def currentLevel = child.currentValue("level")
    if (currentLevel != hubitatLevel) {
        child.sendEvent(name: "level", value: hubitatLevel)
    }

    def shadeValue = (hubitatLevel == 100) ? "open" :
                     (hubitatLevel == 0)   ? "closed" :
                                             "partially open"

    if (child.currentValue("windowShade") != shadeValue) {
        child.sendEvent(name: "windowShade", value: shadeValue)
    }
}

// --- ANGLE ---
if (data.currentAngle != null) {
    child.sendEvent(name: "angle", value: data.currentAngle as Integer)
}

// --- BLIND TYPE ---
if (data.type != null) {
    def blindName = blindTypes[data.type] ?: "Unknown"
    child.updateDataValue("blindType", data.type.toString())
    child.updateDataValue("blindTypeName", blindName)
}

// --- OPERATION ---
if (data.operation != null) {
    child.sendEvent(name: "operation", value: operationTypes[data.operation] ?: data.operation)
}

// --- LIMIT STATE ---
if (data.currentState != null) {
    child.sendEvent(name: "limitState", value: currentStates[data.currentState] ?: data.currentState)
}

// --- VOLTAGE MODE ---
if (data.voltageMode != null) {
    def voltageModeName = voltageModes[data.voltageMode] ?: "Unknown"
    child.updateDataValue("voltageMode", data.voltageMode.toString())
    child.updateDataValue("voltageModeName", voltageModeName)
}

// --- BATTERY ---
if (data.batteryLevel != null) {
    def batteryLevelVal = data.batteryLevel as Integer
    child.sendEvent(name: "batteryLevel", value: batteryLevelVal)

    def batteryPercent = Math.min(100, Math.max(0,
        (((batteryLevelVal - 700) as double) / 150.0 * 100) as Integer
    ))
    child.sendEvent(name: "battery", value: batteryPercent)
}

// --- CHARGING ---
if (data.chargingState != null) {
    def isCharging = (data.chargingState == 1)
    child.sendEvent(name: "chargingState", value: isCharging ? "charging" : "not charging")
}

// --- WIRELESS MODE ---
if (data.wirelessMode != null) {
    def wirelessModeName = wirelessModes[data.wirelessMode] ?: "Unknown"
    child.updateDataValue("wirelessMode", data.wirelessMode.toString())
    child.updateDataValue("wirelessModeName", wirelessModeName)
    child.updateDataValue("isBiDirectional", (data.wirelessMode == 1) ? "true" : "false")
}

// --- RSSI ---
if (data.RSSI != null) {
    child.sendEvent(name: "rssi", value: data.RSSI)
}

}

def updateTDBUDeviceStatus(child, Map data) {
def operationTypes = getOperationTypes()
def currentStates = getCurrentStates()

// --- TOP POSITION ---
if (data.currentPosition_T != null) {
    def bridgePosTop = data.currentPosition_T as Integer
    def hubitatTop = 100 - bridgePosTop
    child.sendEvent(name: "levelTop", value: hubitatTop)
}

// --- BOTTOM POSITION ---
if (data.currentPosition_B != null) {
    def bridgePosBottom = data.currentPosition_B as Integer
    def hubitatBottom = 100 - bridgePosBottom
    child.sendEvent(name: "levelBottom", value: hubitatBottom)

    def shadeValue = (hubitatBottom == 100) ? "open" :
                     (hubitatBottom == 0)   ? "closed" :
                                              "partially open"
    child.sendEvent(name: "windowShade", value: shadeValue)
}

// --- AVERAGE LEVEL ---
if (data.currentPosition_T != null && data.currentPosition_B != null) {
    def hubitatTop = 100 - (data.currentPosition_T as Integer)
    def hubitatBottom = 100 - (data.currentPosition_B as Integer)
    def avgPos = ((hubitatTop + hubitatBottom) / 2) as Integer
    child.sendEvent(name: "level", value: avgPos)
}

// --- OPERATIONS ---
if (data.operation_T != null) {
    child.sendEvent(name: "operationTop", value: operationTypes[data.operation_T] ?: data.operation_T)
}
if (data.operation_B != null) {
    child.sendEvent(name: "operationBottom", value: operationTypes[data.operation_B] ?: data.operation_B)
}

// --- LIMIT STATES ---
if (data.currentState_T != null) {
    child.sendEvent(name: "limitStateTop", value: currentStates[data.currentState_T] ?: data.currentState_T)
}
if (data.currentState_B != null) {
    child.sendEvent(name: "limitStateBottom", value: currentStates[data.currentState_B] ?: data.currentState_B)
}

// --- BATTERY ---
if (data.batteryLevel_T != null) {
    child.sendEvent(name: "batteryLevelTop", value: data.batteryLevel_T)
}
if (data.batteryLevel_B != null) {
    child.sendEvent(name: "batteryLevelBottom", value: data.batteryLevel_B)
}

// --- RSSI ---
if (data.RSSI != null) {
    child.sendEvent(name: "rssi", value: data.RSSI)
}

child.updateDataValue("isTDBU", "true")
child.updateDataValue("blindType", "9")
child.updateDataValue("blindTypeName", "TDBU")

}

What this update accomplishes

:heavy_check_mark: Prevents all Integer#minus crashes

Because no subtraction happens unless the field exists.

:heavy_check_mark: Works with partial ReadDeviceAck packets

Your logs show the bridge often sends:

{"type":1,"operation":1,"wirelessMode":0}

These updated methods handle that gracefully.

:heavy_check_mark: No behavior changes

All your existing logic stays intact — just safer.

I am also working on some code that should allow Hubitat to get shade position updates when the shades are moved outside of Hubitat via another app. Take a look at what I sent yesterday and then we can look at this if you are interested.

I will take a look at this, I know nothing about writing code so it's all AI doing the heavy lifting. I messed something up and am reworking some of the logic. I will also feed the info you sent info my ai and see what we can teach it.

I am interested in seeing your code (if we can get it integrated I will) I know my code polls the bridge and updates the location based on what the bridge says, I've tested it on my my blinds with the connected app as well as the remote I have that connects directly to the blinds and not the hub and Hubitat updates to the correct location, I wonder if this is a Uni vs Bi directional communication thing.

I'm looking forward to see what you are working on.

Hubitat doesn't update the shade position if I move them with the connector app and the code update I was working on didn't work either so I am back to the drawing board at present.

Everything else works fine now and is error free in the logs.

Not sure if it might be related to the unknown device type for the controller that is showing in the dashboard. That is the only anomaly I see currently.

Thank you for the screen shots and your Copilot chat, I've had my AI make the changes so hopefully some null responses are handled better.
I updated the drivers on github you can use the links below to import into hubitat

Parent and Child drivers bumped to Test v29

Parent Driver
Link removed to prevent confusion

Child Driver
Link removed to prevent confusion

Sadly I'm pretty sure the location stuff is because the roller shade motor you have is uni-directional.

below is an except when I searched "DD7002B Connector Bridge convert motors from Uni to bi Directional"

  • Bidirectional Capability: The bridge is compatible with both Bi-directional and Uni-directional motors.
  • Bi-directional Communication: If used with modern Dooya bi-directional motors, the DD7002B allows for feedback, meaning it can receive position information (e.g., how open the blind is) and display it within the app.
  • Uni-directional Support: For older Uni-directional motors, the bridge transmits commands to the motor (opening/closing) but does not receive status updates back from the motor, essentially acting as a one-way remote control.

I'm pretty sure the only way for you to get the location info is to upgrade/replace your motor, or add a bunch of door/window sensors (both options are probably more cost/trouble than it's worth). Of course that's just my opinion.

I've got an idea but they're all pretty rough (aesthetically as well as function and in my opinion cost) off the top of my head is a zwave or zigbee door sensor or an esp8266, flashed with ESPhome or Konnected's ESPHome firmware) tucked away in an appropriate location with power with hard wired door/window switches surface mounted w/ double sided tape at specific levels and have the Magnet installed on the bottom of the screen itself. you could use rule machine to write a rule that depending on which sensor is closed you would then know about where the screen is there It won't be completely accurate but I could see it being within a couple percentage points you could setup a sensor at fully open, 1/4 closed, 1/2 closed 3/4 closed, and fully closed depending on sensors you could probably use more and get a more accurate location I know most have a 3/4"-3" Max gap limitation The smaller the gap the closer and more sensors you can place on your frame.

Thanks for the update and additional research. I agree with what you are saying on the position reporting. I don't think I will add any additional hardware but if I did I would consider a remote garage door controller that is wireless and has a position input that connects to a door contact. Or, I just look at my camera. :slight_smile:

I will test these updates. Give me a day or so. Tks!

@scubamikejax904 Testing update. Code installed and appears to be working well.

I noticed one small thing in the logs and at startup in that the shades were unable to determine position but once I ran them up and down the app went from Open to partially open to to closed as expected and worked fine going from closed to open.

One thing I did see in the logs is that when movement tracking stops at final position and the next command to change position is received it indicates "no final position received using fallback 0". Not sure if movement tracking should have reported that position or not. Doesn't seem to be a big deal just an observation.

Other than that and the Unknown device type in the devices that wasn't present when we first started tested everything is working!

Screenshot 2026-04-03 062412

I think it is related to the null value reported for info.devicetype

I will take a look at those errors but I think the errors are due to the Uni-directional motor communication, I'm wondering If I can have the driver report things differently depending on the motor communication (UNI vs BI) so when the motor doesn't report a location (Uni only receives commands) the driver doesn't throw an error.

I think i've figured out the app's device tab issue, Figured it out you're looking at the bridge device (there isn't anything that you can control from the app so it doesn't know what to do with the device there aren't any capabilities (windowshade, level, etc) but your actual screen devices should show up correctly) the easiest way to fix this is remove the bridge from the room (if you have rooms setup) if not setup rooms and move the devices you want to control into those rooms, this will also put all the devices not setup in a room in a Devices without room room that you can just ignore

1 Like

got the updates uploaded to github

Update links removed v30.1 Parent driver was a bad update

1 Like

I cleaned up the parent driver a little, I made it so that it would show the bridge being online when it received a response from the bridge over UDP (the multicast heartbeat was unreliable in Hubitat) bumped the roller blind child driver back to v30 (the v30.1 fix messed more up than it fixed, luckily I hadn't "fixed" all the child drivers before I did my testing)

Parent driver bumped to v31 with the above online/offline change, I have been running it for a day now and have had no issues.

@jcongdon01
New test version of the parent driver this one should have everything working (including the heartbeat)

Parent driver test v32
https://raw.githubusercontent.com/scubamikejax904/Connector-Bridge-Hubitat-direct/refs/heads/main/Test%20-%20Driver%20-%20Parent

I just dropped it in and while give it a test. Logs look great so far.