Going to next level of Aquarium Automation...who's with me?

I have just started setting up a marine aquarium (110g) and I am trying to automate as much as possible. I did go with a Neptune Systems Apex controller because people have been able to make Home Assistant work with it.

It doesn’t support sending MQTT unfortunately, but I am not letting that stop me. In my quest to keep things cheap I purchased two of these lights http://a.co/d/3JE2o1i I went with 2x24" lights instead of 1x48". The cost wasn’t much different but each 24" puts out about the same light as the 48".

These are supposed to be smart lights but they have horrible controllers. If they lose power they lose their clock and programming. I set about trying to figure out how they were controlled. When I pulled the controller there were 4 wires. My first thought was power to the controller (which is contained in the end cap) and two communications lines. I hooked up a cheap analyzer to identify the protocol in use. Turns out I was over thinking this.

Wire 1 is +5v, Wire 2 is GND (which passes through to the power connector. More on why this is awesome later), Wire 3 is Blue, Wire 4 is white. If you pull 3 or 4 high with a 5v signal it switches on that color. This couldn’t be easier.

I flashed an ESP8266 wemos D1 with Tasmota and set about converting these lights into remotely controllable lights. I marked one light as the master and the other as slave. For the master light, I hardwired the 4 wires into the D1. +5 and ground were easy. I had to change the function on 2 of the digital output lines. After start up I was able to login to the Tasmota interface and toggle both lights. For the slave light I soldered in a 2 pin connector. On the 4 wires for the slave I just clipped the +5 and gnd lines short. Added a 2 wire extension to the blue and white wires and plugged them into the D1. Now I was able to control those lights as well.

Just a bit on the gnd thing. In digital logic, everything has to reference the same ground level. This means for 2 separate items like these lights, you have to tie ground together. Had the input ground been isolated from the controller ground I would have had to pull a 3rd wire for ground to the D1. In this case they were tied together by a common power plug (I replaced the 2 power supplies with a single larger one.)

DO NOT TRY TO TIE YOUR 5V LINES TOGETHER. These lights take in 15V and step it down to 5V for the controller. Since they have separate 5v regulators and the grounds are not isolated tying them together can create some weird problems if not damage. It’s not possible for both regulators to be at precisely the same voltage. This can cause the lower voltage one to sink more current from the higher one to try to bring the voltage down. This causes the higher one to source more current to compensate. Essentially they fight each other for control. Power supplies must be designed for bridging to make this work. Fortunately for this project it’s just not needed.

Next up, I am going to modify a cheap rotary feeder with a D1 to make it controllable. The one I found is easy to disassemble and there is actually a lot of room inside.

3 Likes

I just did something very similar. Here’s some info on how + the python script to make it work. Auto Fish Feeder by sfgabe - Thingiverse

1 Like

So I have decided to use my pi zero temp probes I made to control the heater on my frag tank. The problem I occasionally run into is the script seems to hang occasionally and will just freeze the temperature reading at the last temperature it read. This has rarely happened when the heater has been on fortunately (also the heater’s internal thermometer will keep it from overheating anyway) but in the winter when the script hangs it can drop the water temp quite a bit. I’ve seen it as low as 69 F.

My question would be is there a way to write an automation in HA that would detect the temp has been the exact same for the past half hour or so and then reset my pi zero? I have the pi zero plugged into a sonoff 4ch so I could send a command through home assistant to toggle the relay off then back on. I just don’t know if the proper automation parameters may exist to do this.

Thanks for any insight

Ciwyn,

You can write something in HA to do what you say, but that adds complexity and I’d say fix the script first (or PiZero) - that might be easier too.

Is this script running as part of HA or is it a bash / python or some other scripting language?

I’m running a bash script on my oldest Pi B. At 7 years old, it’s still running, but my slowest Pi of them all and is planned for replacement with a 3B. But it’s the Pi with the highest uptime without reboots. It’s just a dead simple script that parses temps off the wire and pipes it to the mosquito mqtt submit command with args and goes down a list of 10 probes, waits 30 seconds and runs again. There’s actually two such scripts - one for Temp probes and the other for Float Sensors. Your’s should be this reliable as well. :slight_smile:

More details please :slight_smile: Let’s see if there’s an easy fix & you can still monitor your temp as you wish.

The automation in HA is super easy - it’d just an state trigger in automations using the time function and checking if the value stayed the same for more than an hour or two or six. In fact, it’s shorter to type out than my entire explanation. lol

Below is an example of what you’d need, I believe. I’ve copy / pasted the example from the URL beneath it, and #'d out the bits you don’t need - leaving them for a reference for the page I took it from under STATE TRIGGER. It’s only interesting if you want those optional bits back in to use.

Basically it looks to see if the state of sensor.temp_probe_3 has been the same for 2 hours, if so, it’ll trigger.
You may need to fine tune the 2 hours value for your setup / tank.

automation:
  trigger:
    platform: state
    entity_id: sensor.temp_probe_3
    # Optional
    # from: 'not_home'
    # Optional
    # to: 'home'
    # If given, will trigger when state has been the to state for X time.
    for:
      hours: 2
     # minutes: 10
     # seconds: 5

WHAA??? I just saw this. Awesome bro!

I look forward to your component, but think I can work with this with the input sliders! lol

Got some days coming up it’ll be quiet around the house & I’ll have some time to get started with this. I can hardly wait.

Thank you!

It’s the script we worked out last year. Just a basic python script that in general is quite reliable but maybe less than half a dozen times has hung for reasons I’m not quite sure. Restarting the pi zero has fixed it every time.

I’m not home now so I can’t access the actual script but it is based on this script:

import time

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

temp_sensor1 = '/sys/bus/w1/devices/28-#######/w1_slave'
temp_sensor2 = '/sys/bus/w1/devices/28-#######/w1_slave'

def temp_raw1():
    f = open(temp_sensor1, 'r')
    lines = f.readlines()
    f.close()
    return lines

def temp_raw2():
    f = open(temp_sensor2, 'r')
    lines = f.readlines()
    f.close()
    return lines

def read_temp1():
    lines = temp_raw1()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = temp_raw1()
    temp_output1 = lines[1].find('t=')
    if temp_output1 != -1:
        temp_string1 = lines[1].strip()[temp_output1+2:]
        temp_c = float(temp_string1) / 1000.0
        temp_f = temp_c * 9.0 / 5.0 + 32.0
        return temp_c, temp_f

def read_temp2():
    lines = temp_raw2()
    while lines[0].strip()[-3:] != 'YES':
        time.sleep(0.2)
        lines = temp_raw2()
    temp_output2 = lines[1].find('t=')
    if temp_output2 != -1:
        temp_string2 = lines[1].strip()[temp_output2+2:]
        temp_c = float(temp_string2) / 1000.0
        temp_f = temp_c * 9.0 / 5.0 + 32.0
        return temp_c, temp_f

while True:
        print(read_temp1())
        print(read_temp2())
        time.sleep(1)

Then there is another script which publishes to MQTT. I have to imagine it’s likely the MQTT script which is causing the problem because when I catch the problem I notice my temp graph in HA will say last updated hours ago. If it was a problem with the temperature script the temperature would likely come back as an error. I don’t know how to verify I am correct on that though.

1 Like

I’ve got some basics of a component built now, very early work in progress.

I’ve also been using a custom UI component for it https://github.com/thomasloven/lovelace-slider-entity-row

Need to pull it all together and build something proper that can be contributed back to HA but for the moment this will get you a slider for each color channel, as is. If you add a light called “DT light” it will give you 7 entities called light.dt_light_uv, light.dt_light_violet…etc.

import logging

import voluptuous as vol

# Import the device class from the component that you want to support
from homeassistant.components.light import ( ATTR_BRIGHTNESS,
    SUPPORT_BRIGHTNESS, Light, PLATFORM_SCHEMA, LIGHT_TURN_ON_SCHEMA,
    VALID_BRIGHTNESS)
from homeassistant.const import CONF_HOST, CONF_NAME
import homeassistant.helpers.config_validation as cv

# Home Assistant depends on 3rd party packages for API specific code.
REQUIREMENTS = ['https://github.com/mcclown/AquaIPy/archive/1.0.0.zip#aquaipy==1.0.0']

_LOGGER = logging.getLogger(__name__)

# Validation of the user's configuration
PLATFORM_SCHEMA = PLATFORM_SCHEMA.extend({
    vol.Required(CONF_HOST): cv.string,
    vol.Optional(CONF_NAME): cv.string
})


def setup_platform(hass, config, add_devices, discovery_info=None):
    """Setup the AquaIllumination platform."""

    from aquaipy import AquaIPy
    from aquaipy.error import FirmwareError, ConnError, MustBeParentError

    host = config.get(CONF_HOST)
    name = config.get(CONF_NAME)

    # Setup connection with devices
    light = AquaIPy(name)

    try:
        light.connect(host)
    except FirmwareError:
        _LOGGER.error("Invalid firmware version for target device")
        return
    except ConnError:
        _LOGGER.error("Unable to connect to specified device, please verify the host name")
        return
    except MustBeParentError:
        _LOGGER.error("The specifed device must be the parent light, if paired. Please verify")

    colors = light.get_colors()

    add_devices(AquaIllumination(light, color, name) for color in colors)


class AquaIllumination(Light):
    """Representation of an AquaIllumination light"""

    def __init__(self, light, channel, parent_name):
        """Initialise the AquaIllumination light"""
        self._light = light
        self._name = parent_name + ' ' + channel
        self._state = None
        self._brightness = None
        self._channel = channel

    @property
    def name(self):
        """Get device name"""

        return self._name

    @property
    def should_poll(self):
        """Polling required"""

        return True

    @property
    def is_on(self):
        """return true if light is on"""

        return self._state == 'on' or self._state == 'schedule_mode'

    @property
    def state(self):
        """Get device state"""

        return self._state

    @property
    def supported_features(self):
        """Flag supported features"""

        return SUPPORT_BRIGHTNESS

    @property
    def brightness(self):
        """Return brightness level"""

        return self._brightness


    def turn_on(self, **kwargs):
        """Turn all color channels to given percentage"""

        brightness = (kwargs.get(ATTR_BRIGHTNESS, 255) / 255) * 100
        colors_pct = self._light.get_colors_brightness()

        for color,val in colors_pct.items():

            # means that we limit all channels to a max of 100%, when setting
            # the brightness. The next part works around that, until this
            # support is added.

            if val > 100:
                color_pct[color] = 100

        colors_pct[self._channel] = brightness

        _LOGGER.debug("Turn on result: " + str(colors_pct))
        self._light.set_colors_brightness(colors_pct)


    def turn_off(self):
        """Turn all color channels to 0%"""

        colors_pct = self._light.get_colors_brightness()
        colors_pct[self._channel] = 0

        self._light.set_colors_brightness(colors_pct)


    def update(self):
        """Fetch new state data for this light"""

        sched_state = self._light.get_schedule_state()
        colors_pct = self._light.get_colors_brightness()
        brightness = colors_pct[self._channel]

        self._state = "off"

        if sched_state:
            self._state = 'schedule_mode'
        elif brightness > 0:
            self._state = 'on'

        self._brightness = (brightness / 100) * 255

Caveats right now are:

  • no support for turning on/off schedule (you need to manually do that before using this, or else it will just flash the color change)

    • High priority for me, so I’ll fix this soon.
  • no support for setting more than one channel at once. I think I need to add a service to handle this scenario but I need to do more reading. This is useful for adding automatons for colours, getting it to go to all blues or all whites on command for instance.

    • Also high priority for me right now
  • no support for HD (ie. over 100%) yet. For safety I’m limiting all channels to 100% until I work out how to build the client side validation that would be needed to support this. The python module already has this safety build in though.

    • Lower priority for my current project but something I need to do in the long run. Probably won’t be part of v1, unless someone else wants to work on it.
1 Like

Ciwan - okay, post the actual script when you get home and have time. No rush, I’m heading to bed in just a bit. It’s 2:26am here. :slight_smile:

Ok here is my mqtt script

#!/bin/bash
until [ "$?" != "0" ];
do
#individual temp probe and mqtt commands here
        mosquitto_pub -u myuser -P password -t homeassistant/sensor/fishroom/temp5_F -m "`/home/pi/temp5_F.py`" -h myipaddress
# Sleep in seconds
        sleep 55

done

I changed my -u and -P and the ip but the script works

and here is the temp script:

#!/usr/bin/python
import os
import glob
import time

os.system('modprobe w1-gpio')
os.system('modprobe w1-therm')

base_dir = '/sys/bus/w1/devices/'
device_folder = glob.glob(base_dir + '28-03168a3e25ff')[0]
device_file = device_folder + '/w1_slave'

def read_temp_raw():
    f = open(device_file, 'r')
    lines = f.readlines()
    f.close()
    return lines

def read_temp():

Sorry it took me so long to finally get these. I pretty much forgot how to SSH into my pi and had to get a new router so it forced me to actually do it.

I can’t remember who was talking about Seneye on this thread but I wrote a custom component to support directly plugging your Seneye into your RPi and get the data via a native python driver that I wrote as well. Figured I’d add a link to this thread.

There is still the nagging question of does the device store results locally or not. From my reading/testing it seems like if you leave it in interactive mode (“HELLOSUD”) then it doesn’t cache local results and fill up. I guess further testing will reveal that. I’ll figure out a way around that if I have to.

1 Like

Fun thread! Very inspiring. We keep a 30 tank goldfish breeding room, so obviously aquarium threads are very intriguing. I’ve just recently found Home Assistant and am almost happy with our basic setup for the house, but I’d love to eventually do more with the fish room. We have lights and our central water change system on there, but very little in the way of monitoring besides a motion sensor for room temp/turning on the lights and a few leak detectors. I have a ton of Arduino stuff I never really got into because it was over my head at the time, but this is making me want to dig it out again :slight_smile:

1 Like

Hi all,
wow to begin with. This thread answered questions i had :slight_smile:
I’m doin some small time breeding too, fresh water.
Have lights and temperature in HA at the moment. Using Fibaro universal sensor for temperature.
Have thought about ph and other values and after reading this thread i will start looking at this again :slight_smile:
Thanks :slight_smile:
I will be lurking :stuck_out_tongue:

2 Likes

Welcome to the thread @aktill & @sabbath. :slight_smile:

I hope it’s useful for you both & please feel free to share your journey’s and experiences with the rest of us. We’re all learning together. I sometimes go quiet because other day job work keeps me busy but I still lurk & follow up what others are doing and contributing.

BTW, if there’s anyone in this thread who’s in the Netherlands / Germany / Belgium / UK & can make it to Hack in the Box Amsterdam HaxPo on May 9 & 10th, I’ll be there hosting the Wireless Hacking Village - come on over (it’s free to the public, you just have to register before hand on the website) and let’s meet face to face! :slight_smile:

Just a status update - I’m one year and 10 months into using Home Assistant for total system control and management of 8 aquariums at the moment & loving it still. I stopped with breeding clownfish after a successful run…too successful, still trying to sell off the last babies from last year. But the flexibility of Home Assistant to scale up and down economically (approx 300-350 euros vs. approx 15,000 euros for a multiple redundant Apex controller setup) is a serious boon and win.

I finally got around to setting up TTS Voice & Sound Effect Alerts last year, which is super nice on several levels. My primary controller actually sits upstairs, away from the tanks & on a completely different circuit breaker than the aquariums downstairs & pushes TTS Voice messages over MQTT to the Remote HA Pi’s downstairs & on every floor. That way I only have to change / add the TTS voice alerts on a single HA instance, rather than duplicating on every Remote Pi that has a speaker attached to it. I have alerts for Kalkwasser / Top Up problems, Tank Overflow Alerts, Status Alerts during the wholly automated Water Change Processes (cause that sometimes caused an alarm with the wife, when she didn’t know before hand I was running one. lol), as well as voice prompts for home automation & security. Just try to get an APEX or competing aquarium controller to do all that. :wink:

Enjoy!

1 Like

Thanks! Been learning a lot.

In terms of voice alerts I just leverage our Alexas. I can call any of them directly with TTS, and so for water change fills I have a series of notifications that go out (tank filling, tank full, tank drained). I don’t have ours completely automated because I don’t trust auto dosing of Seachem Safe, so that’s a manual step. I then turn on the change pump by voice, and it lets me know when the tank is drained (we change daily from a 150 gallon holding tank).

I also have the intention of voice alerting based off some Smartthings leak sensors (duck weed causes the odd issue), but I don’t want to buy a ST hub and I haven’t quite figured out Conbee/ST playing nice yet.

I did recently figure out how to make our Fluval 3.0’s play nicely with a timer, so I can get a few ramp on/off periods over the day (that’s sort of nice).

Otherwise, just a lot of wet sleeves keeping all the babies fed and happy.

1 Like

Before I found home assistant I was working on an Alexa custom skill to allow me to use voice to log all the things I do around the fish room (dose ferts, change water, start and end quarantine etc). It’s a big job, but it was coming along slowly and steadily.

After finding HA, I of course wanted to start displaying those results graphically in my floor plan layouts. Ideally, I’d have visual alerts when I filter was due for cleaning etc (with 30 tanks, they aren’t getting done each week).

Think I’ve finally cracked how to read my DynamoDB in Node Red, so now it’s just a case of figuring out how I want to show things in the floor plan. Gets a little squinty, so still a work in progress.

On other fronts, I just bought a Nest temperature sensor which I can’t seem to read in HA, and my SmartThings water leak sensors are becoming a PIA. I was hoping to read them with ZHA and a Conbee stick (not supported in Deconz), but I don’t quite yet understand how to read them (work in progress).

I’ve also decided to at some point hook a spare Arduino I have up to HA in some fashion (to drive some fish room tank temp and level sensors), but that’s a whole kettle of fish in terms of communicating with my wifi HA Pi etc.

Making progress though!

1 Like

Dude! I finally had some free time to try the pyseneye & Seneye component you made for us. Awesome! Now I just have to order some new slides. Thank you!

Also, back when I setup my Seneye through the API interface, I made my own icons for pH, NH3, O2, NH4, and light values. (see screenshots) Dunno if there’s a way for you to include them as part of your component but I’m happy to contribute them to the HA component. Just tell me where to send / upload them. :slight_smile:

Well done!

20 13

Glad to see someone else is getting some use out of it :slight_smile:

Great icons! I think the best way to get them included is to contribute them back Material Design Icons, then I can change to using them once they’re accepted there. https://materialdesignicons.com/contribute

1 Like

I found this may interesting for finding NH4 value from dissolved NH3


refer from https://www.jmaterenvironsci.com/Document/vol8/vol8_NS/522-JMES-2876-Purwono.pdf

1 Like

@cowboy I’ve released a more complete version of my AquaIllumination component. Finally did a write up on it as well. Figured I’d add a link back here as well, since this is pretty much definitive aquarium thread.

2 Likes

Hi,

I have been following your project for quite a long time just reading through and through trying to see how i can put it into my use as i don’t own a aquarium but i do hobby hydroponics and the hobby has gone quite a big now changing water from tanks and dosing plants is just a head ache so for nothing is problem running dosing pumps on 12v with input slider as how long it will run the relay the pump is plugged into seconds it runs so its 1ml per second setting achieved by putting a speed controller in between the pumps and controlling their pumping speed till i got to my 1ml/sec.

Please i would like your and the community help into i want to integrate pH, EC dissolved sensors and i am not a coder or anything but i follow any guide and tweak things like anything please if any one can point me this direction how can connect Ph and ec sensors to HAssio it will be a great help into next direction

thanks in advance.