Yet Another Smart Camper Project

I know many similar projects/topics exist on this forum, but I felt like I was hijacking other OP’s topics when posting parts of my own project. I have integrated some things I had not read elsewhere, so I figured I’d share. I’m new to HA as of this spring - and until 2-3 months ago was just using it as an Espresense and MQTT broker supporting my home Hubitat. But HA made the most sense for the camper right out of the box because it already supported a lot of things in my camper.

Home Location/Altitude/Weather - I use a Verizon Mifi hotspot which happens to have built in GPS support - in the form of an NMEA data stream. I set up a shell command and script that, when the camper is away from home, gets the current latitude, longitude and elevation every half hour and updates HA’s current home location. When the camper is back on the home network, it defaults back to the home location and the 30-minute automation stops.

Shore Power Surge Protector - there was already an esphome project for the Hughes Power Watchdog. I just modified it slightly- mainly to include API support, but also to suit a couple other preferences as well.

Propane Tank Gauges - obviously Mopeka - I already had these because of their proven accuracy over other gauges, and these are initially what pushed me towards HA over others.

Water Tank Level Sensors - I have three tasmotized Shelly Plus Unis - for the fresh, gray and black water tanks. One output activates the tank sensor, the other output connects the ADC circuit (this was necessary as to not throw off the manual button LED readings), and the ADC input measures voltage which is inversely converted to percent full. The tank sensors activate sequentially every half hour and publish to MQTT.

Battery Monitor - PZEM-017 was used for this. I found some instructions online to modify this for a 24v boat application - where a D1 Mini is connected ahead of the TTL to modbus converter and gets a direct read from the shunt without additional parts. I modified this for a 12v application and it all fit back into the same PZEM enclosure. That said, this board cannot determine the direction of current (charge vs discharge) so it will be replaced soon.

Awning - A zooz zen53 was used for this. Additionally I put a zooz tilt sensor on the stairs to disable the zen53 zwave and local controls when the stairs are up. Additionally, I use Espresense for disabling/enabling control. So, my wife or I must be present -and- the stairs must be down for the awning to be able to be controlled - either manually or through zwave.

Keyless Entry - I installed a latch.it keyless entry lockset when we first got each of our two campers. On this project, I sacrificed one key fob and a tasmotized d1 mini to allow for lock or unlock of the camper door. Again, I used Espresense for the unlock helper. My wife or I must be present to unlock the door. Locking can be done remotely.

Lighting - all lighting except for storage bay lights are connected to HA using zen16/17’s where they fit, Shelly 1’s where they didn’t, and Shelly RGBW2’s where I could get to the negative wire. Some of the Shelly’s are tasmotized for better control.

Smart Switches - in several locations, I replaced the existing toggle switches with double throw momentary switches. I also added a single throw momentary switch in the bunk. The momentary switches are tied either directly to the switch input on the Zen16/17’s, a tasmotized d1 mini, or to tasmotized RGBW2’s. For the d1 mini, I set up single, double and triple tap actions to control other lights that don’t have switches. For the RGBW’s, I have single tap for on/off, press and hold to dim up, press and hold again to dim down, and double/triple taps to control other lights/fans.

Basic ceiling exhaust fan - We have the basic Maxx Fan with two buttons - an off button and a speed control (1-2-3-4) button. I tucked a tasmotized Shelly plus uni up inside and paralleled the two outputs to the two buttons. I also tied the fan control board to the ADC input. I configured a “virtual” relay on an unused GPIO and exposed it to HA. Tasmota rules allow for control and on/off status of the fan. I also expose the speed button to adjust speed. Hey Siri turn on/off the camper ceiling fan effectively controls the fan.

Wall mount fan - This fan is a Caframo Sirocco II fan, apparently popular among boaters. It is a 3-speed fan with a single button for control (off-1-2-3). Again, a tasmotized Shelly was tucked in, and again an output was paralleled to that button, and again the adc input was connected to the fan control board output. This time though, I set up a virtual PWM dimmer and convert the ADC input to the current fan speed and set the PWM status accordingly. Conversely, setting the PWM will adjust the speed accordingly. With a fan template in HA, I can now control and set speed like any other fan control. Through the tasmota rules, the number of “button presses” needed to get from the current speed to the target speed are performed through the output. So, I can ask Siri to set a fan speed and no matter the current fan state, that speed is set. Hey Siri, set the camper bunk fan to off/low/medium/high sets the fan accordingly.

HVAC - I connected an output from a zen16 to the thermostat connection on the furnace. Then connected the thermostat to the zen16 input. This allows for thermostat or HA control of the furnace. Separately, I have a dumb line-voltage controlled AC unit with no thermostat. For this, I am using an Aeotec heavy duty switch on the line side of the AC unit. I also hardwired power to a Xiaomi e-ink temp/humidity sensor clock. Using the dual mode generic thermostat, I can now have a single HA thermostat that controls heat and cool.

Misc Temp Sensors - I use the small Xiaomi temp humidity sensors in the bathroom and fridge and a govee sensor in the freezer.

TV’s - fortunately, HA has integrations for our Vizio and LG TV’s… and for the main 12v camper TV, I already had a CCWGTV there - using CEC.

Network Connectivity - I wanted one common WiFi network between the house and the camper, and I wanted the camper to be on the home network when at home. So, I feed both a power line connection over the house shore power as well as the Verizon Mifi hotspot into my wireless access point - with the Mifi fed through a usb powered network switch. Both the home router and the Mifi are set up with the same DHCP range and IP assignments for the camper devices. I use a tasmotized XY-WFUSB with rules set up to ping a specific device on my home network. If the device is found, the WFUSB kills power to the Mifi network switch. If it is not found, it turns the switch back on. I know this is sloppy network management, but has worked flawlessly for me for a couple months. This also triggers automations to enable/disable Tailscale - which I only need running when on the Mifi.

Voice Control - A HomePod mini seemed like the obvious choice here since it can be powered easily off the camper 12v and gives me remote Siri/homekit control.

Pushing IPhone Automations - I managed to get a 10DLC campaign approved through twilio. I use this to push data from HA to our phones. On our phones, I silenced all notifications from my twilio number. I then set up iPhone automations which parse the twilio text messages and act on that data. For example, “Siri, find my camper” triggers an HA automation which text messages me (or my wife) the camper’s latitude and longitude. An iPhone automation is then automatically triggered that opens Apple Maps with directions from my current location to the camper. This is helpful when my wife and daughter come meet me at a site I’ve already set up. She can hop in the car, “Siri, find my camper” and within 10 seconds directions pop up on her CarPlay.

Presence - for this I use Espresense - including our phones, watches and cars. The phones and watches are connected to my wife’s and my “persons” in HA to show home/away status. The car beacons are used to illuminate the camper exterior when arriving back to camp after dark - if the camper is away from home. While at home, a driveway sensor illuminates the exterior after dark. Our long driveway is dark at night and the camper sits right next to it so I wanted to make sure anyone pulling into our driveway clearly sees the camper - so they don’t accidentally hit the stairs if they are out.

To Do:

  • Z-wave smoke detector
  • Interface to gas detector - still need to figure this out
  • Replace the PZEM-017 with something that can measure direction (charge vs discharge)
  • Water pump (possibly)
  • Tasmotize the rest of the Shelly’s (tasmota seems to have more reliable WiFi reconnection)
  • Dashboards, dashboards, dashboards!

I’ll post back if I think of anything else that I’ve missed here. It’s been a mad dash the last couple months making the camper smart - a lot of late nights and a lot of :beers:.

Wow, great project! I’m also building a camper from a van at the moment and implementing as much HA as I can. It is a lot of work…especially the dashboards etc. Did you also find the Guition 480x480px touchscreens? I’m implementing one at each door, the bed, etc to control everything around that area, so I don’t need to grab my phone each time. Also got an RF implant in my hand which I want to use to (un)lock the doors. I hope you keep posting, when I got more time I want to create a topic as well for inspiration (and help maybe :wink: )

I did not know about these devices, and have not ventured into LVGL (or even Berry on tasmota), but it’s on my list to explore. Thanks for the suggestion.

Edit: I just ordered one of these displays. Thanks again for the suggestion.

Edit 2: I received my Guition touchscreen. I had to flash openhasp the “hard” way, but got it loaded. I also don’t need the relay and don’t like that the device needs to be mounted in a box as a result. So, I removed the relay, along with the header it plugs into. I ”implanted” a tiny 12v to 5v power converter inside behind the screen and fed the two 12v wires out through the hole where the header stuck through the back cover and filled the rest of that hole with hot glue. Finally, I cut the relay enclosure/mounting plate flush so that I can still use the mounting holes. So now I just need to drill a small hole in the camper wall to feed the 12v wires through and the device will sit flush to the wall. Now that power and mounting is figured out, I’ll start working on the screens. I’ll post photos once complete.

Auto-Switching Remote VPN Connection:

When my camper is connected to the home network, I use my home router’s VPN connection to access HA remotely. And when the camper is connected to the cellular network, Tailscale is automatically enabled on the HA for remote access.

Combining some of the concepts in my OP, I push a “variable” through twilio to my iPhone (using an iPhone automation and reminder list). Separately, I have a shortcut on my Home Screen that when run, checks if I am connected to my common home/camper WiFi SSID, and if not, checks that variable, connects to the appropriate VPN connection (L2TP or Tailscale) and then loads my HA URL.

Now that the camping season is here AGAIN, I am back to work on this. I finally got around to the guition 480x480 touchscreen. I ended up 3D printing a new mounting backplate - looks cleaner than the hack job I did on the relay housing - and it snaps in pretty snug. I have it mostly programmed - just need to add some status icons in the title bar (batteries, tanks, propane) and a thermostat for the AC/Gas Heat. I use a little electric heater through the winter to keep everything above freezing so I did “borrow” and modify a thermostat screen I found online. I’ll post back final pictures once installed.

The touchscreen interface is a lot better than I expected. I may buy a 7" next for above the bed.


Alright, more work on my guition touch screen. I scrapped the thermostat control that I borrowed and came up with a much more robust multi-mode thermostat control. I also added status for the battery, propane tanks and fluid tanks to my titlebar.

For the titlebar status, each of the tanks will annunciate status by color - green, yellow, red. For the batteries, it shows charge/discharge status as well as state of charge.

For the thermostat, I created a “dual-heat switch” template switch that will control my plugin electric heater if available or the gas furnace if the electric heater is not available. I then combined that with my dumb AC control (aeotec heavy duty smart switch controlling the feed to the AC unit) into the dual-mode generic thermostat. I then created a multi-mode thermostat control for the guition.


Cool, I’m on the same boat, ehh…van :slight_smile: Building the van right now and have about 5 480x480 display’s to place on at each door, cockpit, bed etc. Added an ESP32 to about everything which is running on 12V and not connectable, so I can embed it.
Are you willing to share your baseplate file?

Assuming you’re referring to the mounting plate, and not the plate jsonl file, here are two versions - one that’s inset in the middle to allow more screw head clearance if you need it and one that’s a flat plate. I prefer the flat one, but the inset may print better due to the added supports. IMPORTANT - print this vertically with the tabs oriented to the left and right - otherwise the tabs will likely just snap off.

flat.stl

inset.stl

FYI, these displays are now selling on Ali Express without the relay and they’re under $20 USD including shipping. I just ordered 2 more.

Yes, I meant the stl files, thanks a lot, may save me some time creating myself.

They are getting cheaper each time! Thanks for the tip and good luck with your van!

hey, really great thermostat, can you share the yaml?

I did this in openhasp, but below are the relevant portions of my pages.jsonl and openhasp.yaml files.

NOTE: this uses the mdi truetype font file - upload it as mdi.ttf.

NOTE 2: This is based on 0.5 degree target temp step.

NOTE 3: The mode buttons (heat, cool, auto) turn off the climate device before setting the mode. I did this specifically for the camper so I could set new target setpoints when changing modes and not have the heater/AC cycle momentarily.

NOTE 4: I’m still working on optimizing and improving this, but as it is, it works really well in my camper.

pages.jsonl:

{"comment":" ----------- Text ------------"}
{"page":4,"id":4,"obj":"label","x":160,"y":114,"w":160,"h":32,"align":"center","text":"Status","text_font":22,"text_color":"#FFFFFF"}
{"page":4,"id":5,"obj":"label","x":140,"y":150,"w":200,"h":60,"text":"\uE50F 00.0°F","align":"center","text_font":22,"text_color":"#FFFFFF"}
{"comment":" ----------- Setpoint - Heat or Cool Mode ------------"}
{"page":4,"id":6,"obj":"label","x":140,"y":176,"w":200,"h":84,"text":"00.0°F","align":"center","text_font":68,"text_color":"#FFFFFF","hidden":1}
{"comment":" ----------- Setpoint - Dual Mode ------------"}
{"page":4,"id":7,"obj":"label","x":100,"y":182,"w":132,"h":84,"text":"00.0°","align":"right","text_font":60,"text_color":"#FFFFFF","hidden":0}
{"page":4,"id":8,"obj":"label","x":248,"y":182,"w":132,"h":84,"text":"00.0°","align":"left","text_font":60,"text_color":"#FFFFFF","hidden":0}

{"comment":" ----------- Arcs ------------"}
{"comment":" ----------- Background Arc ------------"}
{"page":4,"id":15,"obj":"arc","x":52,"y":40,"w":376,"h":376,"rotation":90,"line_width":28,"line_color":"#232830","line_opa":255,"line_opa10":0,"border_side":0,"min":45,"max":95,"adjustable":false,"start_angle":45,"end_angle":315,"bg_opa":0,"val":0}
{"comment":" ----------- Baseline Points in Dual Mode ------------"}
{"page":4,"id":16,"obj":"obj","x":110,"y":330,"w":28,"h":28,"bg_opa":255,"bg_color":"#A14A1E","border_side":0,"radius":14}
{"page":4,"id":17,"obj":"obj","x":342,"y":330,"w":28,"h":28,"bg_opa":255,"bg_color":"#4473B0","border_side":0,"radius":14}
{"comment":" ----------- Heat Indicator - set hidden to 0 (heat or dual) or 1 (cool or off)------------"}
{"comment":" ----------- Show Knob - set adjustable to true (heat) or false (dual, cool or off)------------"}
{"page":4,"id":18,"obj":"arc","x":52,"y":40,"w":376,"h":376,"rotation":90,"line_width":28,"line_width10":28,"line_color10":"#A14A1E","bg_color20":"#FFFFFF","line_opa":0,"border_side":0,"border_width20":4,"border_color20":"#FF6F22","min":90,"max":190,"start_angle":45,"end_angle":315,"start_angle10":45,"end_angle10":315,"bg_opa":0,"type":0,"val":90,"hidden":0,"adjustable":false}
{"comment":" ----------- Cool Indicator - set hidden to 0 (cool or dual) or 1 (heat or off)------------"}
{"comment":" ----------- Show Knob - set adjustable to true (cool) or false (dual, heat or off)------------"}
{"page":4,"id":19,"obj":"arc","x":52,"y":40,"w":376,"h":376,"rotation":90,"line_width":28,"line_width10":28,"line_color10":"#4473B0","bg_color20":"#FFFFFF","line_opa":0,"border_side":0,"border_width20":4,"border_color20":"#59A1FF","min":90,"max":190,"start_angle":45,"end_angle":315,"start_angle10":45,"end_angle10":315,"bg_opa":0,"type":2,"val":190,"hidden":0,"adjustable":false}
{"comment":" ----------- Current temp ------------"}
{"page":4,"id":20,"obj":"arc","x":52,"y":40,"w":376,"h":376,"rotation":90,"line_width":28,"line_width10":28,"line_opa":0,"line_opa10":0,"border_side":0,"border_side20":0,"min":1,"max":1,"start_angle":200,"end_angle":200,"bg_opa":0,"bg_opa20":128,"bg_color20":"#FFFFFF","pad_left20":-9,"pad_right20":-9,"pad_top20":-10,"pad_bottom20":-9,"val":1,"adjustable":true,"enabled":1,"click":0}
{"comment":" ----------- Arc Fatfinger Protection ------------"}
{"page":4,"id":21,"obj":"obj","x":146,"y":120,"w":188,"h":248,"bg_opa":0,"bg_color":"#A14A1E","border_side":0,"radius":0}
{"page":4,"id":22,"obj":"obj","x":60,"y":368,"w":360,"h":36,"bg_opa":0,"bg_color":"#A14A1E","border_side":0,"radius":0}

{"comment":" ----------- Temp Control Buttons - Dual Mode ------------"}
{"page":4,"id":23,"obj":"btn","x":165,"y":260,"h":60,"w":60,"radius":30,"border_side":15,"bg_color":"#181c18","toggle":"false","border_color":"#FF6F22","border_width":1,"text":"\uE415","align":"center","text_color":"#FFFFFF","text_font":24,"bg_opa00":0}
{"page":4,"id":24,"obj":"btn","x":165,"y":332,"h":60,"w":60,"radius":30,"border_side":15,"bg_color":"#181c18","toggle":"false","border_color":"#FF6F22","border_width":1,"text":"\uE374","align":"center","text_color":"#FFFFFF","text_font":24,"bg_opa00":0}
{"page":4,"id":25,"obj":"btn","x":255,"y":260,"h":60,"w":60,"radius":30,"border_side":15,"bg_color":"#181c18","toggle":"false","border_color":"#59A1FF","border_width":1,"text":"\uE415","align":"center","text_color":"#FFFFFF","text_font":24,"bg_opa00":0}
{"page":4,"id":26,"obj":"btn","x":255,"y":332,"h":60,"w":60,"radius":30,"border_side":15,"bg_color":"#181c18","toggle":"false","border_color":"#59A1FF","border_width":1,"text":"\uE374","align":"center","text_color":"#FFFFFF","text_font":24,"bg_opa00":0}
{"comment":" ----------- Temp Control Buttons - Heat-Cool Mode ------------"}
{"page":4,"id":27,"obj":"btn","x":165,"y":332,"h":60,"w":60,"radius":30,"border_side":15,"bg_color":"#181c18","toggle":"false","border_color":"#FFFFFF","border_width":1,"text":"\uE374","align":"center","text_color":"#FFFFFF","text_font":24,"bg_opa00":0,"hidden":1}
{"page":4,"id":28,"obj":"btn","x":255,"y":332,"h":60,"w":60,"radius":30,"border_side":15,"bg_color":"#181c18","toggle":"false","border_color":"#FFFFFF","border_width":1,"text":"\uE415","align":"center","text_color":"#FFFFFF","text_font":24,"bg_opa00":0,"hidden":1}

{"comment":" ----------- Mode Buttons ------------"}
{"page":4,"id":30,"obj":"obj","x":60,"y":406,"w":360,"h":36,"bg_color":"#232830","border_side":0,"radius":11}
{"page":4,"id":31,"obj":"btn","x":60,"y":406,"w":90,"h":36,"toggle":false,"radius":20,"bg_color":"#232830","bg_color02":"#A9A9A9","border_side":0,"text_font":"mdi24","text":"\uDB81\uDC25","text_color":"#ffffff","radius":11}
{"page":4,"id":32,"obj":"btn","x":150,"y":406,"w":90,"h":36,"toggle":false,"radius":20,"bg_color":"#232830","bg_color02":"#FF6F22","border_side":0,"text_font":"mdi24","text":"\uDB80\uDE38","text_color":"#ffffff","radius":11}
{"page":4,"id":33,"obj":"btn","x":240,"y":406,"w":90,"h":36,"toggle":false,"radius":20,"bg_color":"#232830","bg_color02":"#59A1FF","border_side":0,"text_font":"mdi24","text":"\uDB81\uDF17","text_color":"#ffffff","radius":11}
{"page":4,"id":34,"obj":"btn","x":330,"y":406,"w":90,"h":36,"toggle":false,"radius":20,"bg_color":"#232830","bg_color02":"#FFC107","border_side":0,"text_font":"mdi24","text":"\uDB86\uDE79","text_color":"#ffffff","radius":11}

openhasp.yaml:

    - obj: "p4b4"
      properties:
        "text": "{% if state_attr('climate.hvac','hvac_action') is not none %}
            {{ state_attr('climate.hvac','hvac_action') | title }}
            {%- endif %}"
    - obj: "p4b5"
      properties:
        "text": "{% if state_attr('climate.hvac','current_temperature') is not none %}
            \uE50F {{ state_attr('climate.hvac','current_temperature') }}°F
            {%- endif %}"
    - obj: "p4b6"
      properties:
        "hidden": '{{ 1 if is_state("climate.hvac", "heat_cool") or is_state("climate.hvac", "off") else 0 }}'
        "text": "{% if state_attr('climate.hvac','temperature') is not none %}
            {{ state_attr('climate.hvac','temperature') }}°F
            {%- endif %}"
    - obj: "p4b7"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
        "text": "{% if state_attr('climate.hvac','target_temp_low') is not none %}
            {{ state_attr('climate.hvac','target_temp_low') }}°
            {%- endif %}"
    - obj: "p4b8"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
        "text": "{% if state_attr('climate.hvac','target_temp_high') is not none %}
            {{ state_attr('climate.hvac','target_temp_high') }}°
            {%- endif %}"
    - obj: "p4b16"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
    - obj: "p4b17"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
    - obj: "p4b18"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") or is_state("climate.hvac", "heat") else 1 }}'
        "adjustable": '{{ 1 if is_state("climate.hvac", "heat") else 0 }}'
        "val": "{% if is_state('climate.hvac','heat_cool') %}
            {{ state_attr('climate.hvac','target_temp_low') * 2 }}
            {% elif is_state('climate.hvac','heat') %}
            {{ state_attr('climate.hvac','temperature') * 2 }}
            {%- endif %}"
      event:
        "changed":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: "{% if is_state('climate.hvac','heat') %}
                  {{ val/2 }}
                  {%- endif %}"
        "up":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: "{% if is_state('climate.hvac','heat') %}
                  {{ val/2 }}
                  {%- endif %}"
    - obj: "p4b19"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") or is_state("climate.hvac", "cool") else 1 }}'
        "adjustable": '{{ 1 if is_state("climate.hvac", "cool") else 0 }}'
        "val": "{% if is_state('climate.hvac','heat_cool') %}
            {{ state_attr('climate.hvac','target_temp_high') * 2 }}
            {% elif is_state('climate.hvac','cool') %}
            {{ state_attr('climate.hvac','temperature') * 2 }}
            {%- endif %}"
      event:
        "changed":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: "{% if is_state('climate.hvac','cool') %}
                  {{ val/2 }}
                  {%- endif %}"
        "up":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: "{% if is_state('climate.hvac','cool') %}
                  {{ val/2 }}
                  {%- endif %}"
    - obj: "p4b20"
      properties:
        "start_angle": "{% if state_attr('climate.hvac','current_temperature') is not none %}
            {{ (((state_attr('climate.hvac','current_temperature')-45)*5.4)+45) | round(0) }}
            {%- endif %}"
        "end_angle": "{% if state_attr('climate.hvac','current_temperature') is not none %}
            {{ (((state_attr('climate.hvac','current_temperature')-45)*5.4)+45) | round(0) }}
            {%- endif %}"
        "val": 1

    - obj: "p4b23"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
      event:
        "down":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              target_temp_low: "{{ state_attr('climate.hvac','target_temp_low') + state_attr('climate.hvac','target_temp_step') | float(default=1)}}" 
              target_temp_high: "{% if (state_attr('climate.hvac','target_temp_low') + 4.5) > state_attr('climate.hvac','target_temp_high') %}
                  {{ state_attr('climate.hvac','target_temp_high') + state_attr('climate.hvac','target_temp_step') | float(default=1)}}
                  {% else %}
                  {{ state_attr('climate.hvac','target_temp_high') }}
                  {% endif %}"
    - obj: "p4b24"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
      event:
        "down":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              target_temp_low: "{{ state_attr('climate.hvac','target_temp_low') - state_attr('climate.hvac','target_temp_step') | float(default=1)}}" 
              target_temp_high: "{{ state_attr('climate.hvac','target_temp_high') }}"
    - obj: "p4b25"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
      event:
        "down":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              target_temp_low: "{{ state_attr('climate.hvac','target_temp_low') }}"
              target_temp_high: "{{ state_attr('climate.hvac','target_temp_high') + state_attr('climate.hvac','target_temp_step') | float(default=1)}}" 
    - obj: "p4b26"
      properties:
        "hidden": '{{ 0 if is_state("climate.hvac", "heat_cool") else 1 }}'
      event:
        "down":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              target_temp_low: "{% if (state_attr('climate.hvac','target_temp_low') + 4.5) > state_attr('climate.hvac','target_temp_high') %}
                  {{ state_attr('climate.hvac','target_temp_low') - state_attr('climate.hvac','target_temp_step') | float(default=1)}}
                  {% else %}
                  {{ state_attr('climate.hvac','target_temp_low') }}
                  {% endif %}"
              target_temp_high: "{{ state_attr('climate.hvac','target_temp_high') - state_attr('climate.hvac','target_temp_step') | float(default=1)}}" 
    - obj: "p4b27"
      properties:
        "hidden": '{{ 1 if is_state("climate.hvac", "heat_cool") or is_state("climate.hvac", "off") else 0 }}'
      event:
        "down":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: "{{ state_attr('climate.hvac','temperature') - state_attr('climate.hvac','target_temp_step') | float(default=1)}}" 
    - obj: "p4b28"
      properties:
        "hidden": '{{ 1 if is_state("climate.hvac", "heat_cool") or is_state("climate.hvac", "off") else 0 }}'
      event:
        "down":
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: "{{ state_attr('climate.hvac','temperature') + state_attr('climate.hvac','target_temp_step') | float(default=1)}}" 

    - obj: "p4b31"
      properties:
        "bg_color": '{{ "#A9A9A9" if is_state("climate.hvac", "off") else "#232830" }}'
      event:
        "up":
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.hvac
            data:
              hvac_mode: "off"
    - obj: "p4b32"
      properties:
        "bg_color": '{{ "#FF6F22" if is_state("climate.hvac", "heat") else "#232830" }}'
      event:
        "up":
          - service: openhasp.command
            data:
              keyword: p4b7.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b8.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b23.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b24.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b25.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b26.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.hvac
            data:
              hvac_mode: "off"
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: 50
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.hvac
            data:
              hvac_mode: "heat"
    - obj: "p4b33"
      properties:
        "bg_color": '{{ "#59A1FF" if is_state("climate.hvac", "cool") else "#232830" }}'
      event:
        "up":
          - service: openhasp.command
            data:
              keyword: p4b7.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b8.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b23.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b24.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b25.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b26.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.hvac
            data:
              hvac_mode: "off"
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              temperature: 85
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.hvac
            data:
              hvac_mode: "cool"
    - obj: "p4b34"
      properties:
        "bg_color": '{{ "#FFC107" if is_state("climate.hvac", "heat_cool") else "#232830" }}'
      event:
        "up":
          - service: openhasp.command
            data:
              keyword: p4b6.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b27.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: openhasp.command
            data:
              keyword: p4b28.hidden
              parameters: "1"
            target:
              entity_id: openhasp.camper_entry
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.hvac
            data:
              hvac_mode: "off"
          - service: climate.set_temperature
            target:
              entity_id: climate.hvac
            data:
              target_temp_low: 50
              target_temp_high: 85
          - service: climate.set_hvac_mode
            target:
              entity_id: climate.hvac
            data:
              hvac_mode: "heat_cool"

Edit: Since I’m not always around the house/camper while I work on my jsonl file, I took the time to compile windows native versions of OpenHASP in 7 different screen sizes - 240x320, 320x240, 320x480, 480x320, 480x480, 800x480 and 1024x600 - for testing purposes. If anyone wants a copy of a portable exe file, let me know.

Dynamic Weather and Reverse Geocoding

So, since I’ve only been camping locally over the last year, I had no idea that the stock weather integration (met.no) did not update dynamically based on the dynamic home location. After further research, it seems none of the weather integrations support dynamic locations out of the box. After several hours of searching online, I was convinced I’d have to create my own weather template device and populate forecast data the (really) hard way. Finally, I stumbled upon one reddit post that mentioned the very hidden (top secret) “track_home” setting in the met.no integration.

Steps to make met.no dynamic:

  1. I deleted the met.no service instance that came stock with my HAOS install (not sure if this is necessary)
  2. Re-added the met.no integration (again not sure if this is necessary if step 1 wasn’t taken)
  3. Restart HA in safe mode
  4. Go into the terminal addon and edit .storage/core.config_entries
  5. Locate the line that includes “domain”:“met”
  6. Locate the “data:” entry, which should include elevation, latitude and longitude
  7. Replace the data entry with “data”:{“name”:“Home”,“track_home”:true}
  8. Restart home assistant

Now met.no service/entity will dynamically update based on the home location/coordinate.

Reverse Geocoding:
I only ended up discovering the above problem/solution because I was trying to get the weather entity to update its “friendly_name” attribute based on the current location. That’s when I found the places integration which creates a sensor that takes the current gps coordinates and converts that to the nearest city/county, state, and country. I then discovered the Config Template Card which allows me to override the weather entity’s friendly_name.

Here is my yaml for that card as well as the card itself.

type: custom:config-template-card
entities: weather.forecast_home
card:
  type: weather-forecast
  entity: weather.forecast_home
  show_current: true
  show_forecast: true
  forecast_type: daily
  forecast_slots: 7
  name: >-
    ${(states['sensor.location'].attributes.city ?
    states['sensor.location'].attributes.city :
    states['sensor.location'].attributes.county)+',
    '+(states['sensor.location'].attributes.state_abbr)}

So now, I do actually have dynamic weather, and better yet, the weather card shows the current locale.

Note, the dynamic weather updates immediately upon a location change, but the reverse geocode (city name) takes up to a minute to update (based on my testing).

Edit: I scrapped the Config Template Card approach - it required a page refresh if the location changes. Instead I am now using Card Mod to add the city/state to the weather card.

Shelly Wave 1 LR UL & Misc Upgrades

The Shelly wave 1 LR is finally available on Amazon. So I replaced my Shelly 1’s and I’ve gotta say - this is a great little device. I actually included them over LR from my test bench in the house - over 150’ away. Hopefully they come out with a zwave RGBW dimmer soon.

Smoke detector - replaced with a zwave combination smoke/CO detector.

Battery monitor - replaced the PZEM with a Victron SmartShunt - way better!

Cooktop Hood - I cut in a Zen17 at the hood to control the light and fan. The existing fan/light switches are tied into the Zen inputs to allow for local and zwave control.

So, continuing down the path of dynamic location updates, I realized that although I’m good on home coordinates and weather, I needed a means to update the timezone dynamically as well. I found the Geolocator integration that serves this exact purpose. It also reverse geocodes city and state, so I was able to use this new integration to replace the Places integration.

Then I realized that I need to also update the openhasp timezones as those get their time direct from NTP… Well, the geolocator integration also has an entity with the standard timezone IDs, and I can just update the hasp timezone over MQTT.

So, with a couple simple automations, anytime I’m away from home, the home zone location updates every 30 minutes, which in turn updates the weather (and the city/state name on the weather card); and if the timezone changes,
updates timezone/time on HA, and on my openhasp displays. All with no user intervention.

Edit: and it now also updates the time on the Xiaomi E-Ink Temp/Humidity/Clock.

Another update - finally spent some time putting together a dashboard. Building on the previous/above iPhone shortcut that checks connectivity to HA and if necessary, connects to the appropriate VPN before loading the HA page, I modified it slightly to load HA as a web app for a better UX.

If either of us are near the camper, the unlock icon appears. If we are away, it hides. Additionally if any entity on an entities card is switched on, the all off toggle appears at the top of the card. And of course, the weather card shows our current location and forecast (currently out camping for the long holiday weekend).

Pressing the lock or unlock button obviously locks/unlocks the door. My next challenge is to see if I can tuck a small magnet into the orange lock handle and place a contact sensor on the door below it - to get current lock status… and then template a lock device!

Some miscellaneous other cards and my map card showing our current location.




Thank you for sharing and updating the thread!

Another update:

Tire Pressure - not sure why I didn’t think about it earlier, but I went ahead and ordered a pair of BLE TPMS sensors. I templated them into a single sensor device which indicates if either tire is low or high, or if both are ok.

Consolidate ESP Devices - in an effort to reduce the number of IP devices on my network, I decided to consolidate three esp boards into one. Previously, I had one esp32 for espresense, another esp32 for the Hughes Power Watchdog and and esp8266 for the door lock/unlock. I combined all three into one esp32 board running esphome. I had to switch from Espresense to the Bermuda integration. The challenging part was that when at home, the camper Espresense published to an MQTT broker in the camper that bridged Espresense topics to the house broker. So, I created automations that take the Bermuda devices and publish them to the camper broker as Espresense topics.
As soon as someone offers a zwave RGBW controller, this esphome device is already set up to eliminate another wifi shelly plus rgbw device that is currently set up for a couple of momentary switch inputs.

Next project - I keep an ARB Zero Fridge in my tow vehicle. I am working on creating a bluetooth integration for this - so I can monitor status and control temperature, low batt threshold, and boost mode.

Editing this post as I’m still on the same camping trip. I currently use my Verizon Mifi when away and the home Unifi router over powerline when at home, and each feeds into a WAP in the camper. After a week at this site, I’ve run out my data allotment and my bandwidth has been throttled to an unbearable point. Of course, I only have a windows PC with me - that lacks an ethernet port - and I happened to have a TP-Link travel router stashed in one of the camper cabinets. I managed to throw together a quick setup where the travel router connects to my phone’s hotspot and uses the one available ethernet port to connect to the WAP. I matched the same configurations (DHCP range, IP reservations, etc) to the mifi (and the home router). So a quick swap, and I’m back online with my phone’s hotspot. The reason I posted this - as we all know, when camping, sometimes you have to get really creative to fix mechanical/electrical issues with the tools/materials you happen to have on hand. It’s great that we now live in an age where we are able to do the same electronically.

Curious, are you saying that the Shelly 1 work with 1 wire? I had attempted to make some of my camper lighting ‘smart’ but found that most of my light switches only had 1 wire at them (at least could not find the other one easily).
How does this work? I’m about to be in my camper for a week so may have time to play.

For switching yes - you can switch the positive (or negative) side of the light - which should already be wired to the switch. For dimming maybe - only if you can get to the negative wire for the light(s) you want to dim. As I believe you’ve already noticed, it’s pretty much guaranteed that the camper/RV manufacturer shared the negative wire with all sorts of other things. Every led PWM dimmer I’ve seen has to be wired into the negative side.

You still need to power the module itself, but any +/- wires you can find will work for that. I would also wire the existing switch up to the module so the switch controls the module and the module controls the light. I set my switches so that a toggle in either direction will toggle the lights.

So for our camper living area for example, I had to stick with a Shelly 1 - or now Shelly Wave 1 - because I couldn’t get to the negative wires of all the lights.

For the pairs of lights above the bed or dining table which don’t have switches, I was able to fish a new dedicated negative wire from one light to the other light, widen the hole behind that light and wire up an RGBW and shove it up inside the hole. In a couple of cases I was able to cut in a switch to control the RGBW. In a couple of cases I switch the RGBW by multi-tapping a different zone’s switch. And then of course I can dim/switch through home assistant.

All my lights are the dome/puck style lights with the button in the middle. For the couple of areas that don’t have wired switches, my hope is to rewire the button on those lights to trigger the module - to make them more wife/daughter friendly… but I was kind of hoping someone would come back out with a zwave us rgbw dimmer before I revisit those locations.