First timer... Trying to convert a working script to create support for a new platform

Hello everyone,
After watching HA project for more than a year I decided that this is the home automation platform for me ( coming from ISY & Smartthings), And I would like to help and contribute as much as I can and learn from the other devs here what ever they can teach :slight_smile:

So in the past week I’m working on integration for Aerogarden this is an hydroponic indoor garden that we use to grow harbs and vegetables, I have a working script in python3 that I wrote after taking a look how the IOS app works with fiddler in the middle, I started to play around with the basic sensor example and i ended up with the code below, I can see the sensors with data from the Aerogarden server but the state of the sensor is not being updated once the state is being updated on the IOS app or on the garden itself, I don’t have a lot of experience coding with classes so I’m sure I’m missing something very basic… anyway I would love to hear what you guys think or any comments in general!

Epotex


from homeassistant.helpers.entity import Entity
import logging
import urllib
import requests
import base64
##########

#some aerogarden static vars
DOMAIN = 'dev3'
agent = "BountyWiFi/1.1.13 (iPhone; iOS 10.3.2; Scale/2.00)"
port = "8080"
host = "http://ec2-54-86-39-88.compute-1.amazonaws.com:"

#API Calls
Login_call = "/api/Admin/Login"
SetDictPushCount = "/api/CustomData/SetDictPushCount?userID="
QueryUserDevice = "/api/CustomData/QueryUserDevice"
GetUserSetted = "/api/CustomData/GetUserSetted"
QueryDeviceOnline = "/api/CustomData/QueryDeviceOnline"
QueryDeviceStatus = "/api/CustomData/QueryDeviceStatus"
UpdateDeviceConfig ="/api/CustomData/UpdateDeviceConfig"

##########

def base64decode(b):
    return base64.b64decode(b).decode('utf-8')

def setup_platform(hass, base_config, add_devices, discovery_info=None):
    #getting config vars
    encoded_email = urllib.parse.quote(base_config['mail'])
    encoded_password = urllib.parse.quote(base_config['password'])
    encoded_mac = urllib.parse.quote(base_config['aerogarden_mac_address'])
    #building the auth data
    auth_data = "mail=" + encoded_email + "&userPwd=" + encoded_password
    apiurl = str(host) + str(port) + str(Login_call)
    #creating IOS header
    headers = {
        'User-Agent': 'BountyWiFi/1.1.13 (iPhone; iOS 10.3.2; Scale/2.00)',
        "Content-Type": "application/x-www-form-urlencoded",
        "Connection": "keep-alive",
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate"
    }
    try:
        #building the post request
        r = requests.post(apiurl,  data=auth_data, headers=headers)
        responce = r.json()
        #userID =responce["code"]
        userID = responce["code"]
        device_url = "airGuid=" + encoded_mac + "&userID=" + str(userID)
        apiurl = str(host) + str(port) + str(QueryDeviceStatus)
        #requesting data
        r = requests.post(apiurl,  data=str(device_url), headers=headers)
        garden_data = r.json()
        #extracted info
        totalDays = garden_data['plantedDay']
        nutriRemindDay = garden_data['nutriRemindDay']
        """ Available stats from Aerogarden
        lightStat = garden_data['lightStat']
        pumpStat = garden_data['pumpStat']
        clock = garden_data['clock']
        airGuid = garden_data['airGuid']
        lightCycle = garden_data['lightCycle']
        pumpCycle = garden_data['pumpCycle']
        lightTemp = garden_data['lightTemp']
        config_id= garden_data['configID']
        pumpHydro = garden_data['pumpHydro']
        pumpRemind4Hour = garden_data['pumpRemind4Hour']
        plantedType = garden_data['plantedType']
        garden_name =base64decode(garden_data['plantedName'])
        plantedDay = garden_data['totalDay']
        alarmAllow = garden_data['alarmAllow']
        plantedDate = garden_data['plantedDate']
        nutrientDate = garden_data['nutrientDate']
        updateDate = garden_data['updateDate']
        createDate = garden_data['createDate']
        swVersion = garden_data['swVersion']
        hwVersion = garden_data['hwVersion']
        bwVersion = garden_data['bwVersion']
        oldPlantedDay = garden_data['oldPlantedDay']
        deviceID = garden_data['deviceID']
        deviceIP = garden_data['deviceIP']
        """
        # Adding Nutrition reminder days sensor
        add_devices([add_Sensor("Nutrition Reminder Day", nutriRemindDay, "Days")])
        # Adding Total days planted sensor
        add_devices([add_Sensor("Total Days Planted", totalDays, "Days")])

    except RequestException:
        _LOGGER.exception("Error communicating with AeroGarden")
        return False


class add_Sensor(Entity):
    """Representation of a Sensor."""

    def __init__(self, s_name, parm, status):
        self.s_name = s_name
        self.parm = parm
        self.status = status

        """Initialize the sensor."""
        self._state = None

    @property
    def name(self):
        """Return the name of the sensor."""
        return self.s_name

    @property
    def state(self):
        """Return the state of the sensor."""
        return self._state

    @property
    def unit_of_measurement(self):
        """Return the unit of measurement."""
        return self.status

    def update(self):
        """Fetch new state data for the sensor.
        This is the only method that should fetch new data for Home Assistant.
        """
        self._state = self.parm
1 Like

Even a general direction will help me… :slight_smile: Anything in the documentation that I missed?

I’m not at a point where I could help you develop this (and I don’t have an WiFi Aerogarden, either), but this is a cool project. I was just looking at the WiFi Aerogardens and wondered if anyone had made a component for them yet.

Hopefully somebody else comes along and notice this thread.

Thanks, Still working on it, I’m very close, but not there yet… I got some coding tips in the discord chat, Hopefully I’ll have some time in the next few weekends to nail it.

When you will submit your pull request you will get feedback.
Studying other similar components helped me a lot

Thanks @robmarkcole, I didn’t want to submit a request when I know it’s not working as it should, is it an acceptable way to get feedback? I’m looking at the bitcoin sensor, still a little bit confused about how to force the update of the sensor… :slight_smile:

Hi, yes should be working before submitting, although asking advice on discord is of course what it’s for :slight_smile: Where’s your repo?

Any updates? Do you have a github repository for people to look at?

Hey roofuskit,

Unfortenetly as much as I want I’m unable to dedicate to this project more time, but I created a repo with the latest version of my code here: https://github.com/epotex/hagarden
If you have questions please let me know.

P.S I would love to understand what I was missing.

epotex

I’m not promising I’ll accomplish anything as I’ve never built a HASS component and my Python experience is quite long ago, but I just got the wife one of these for Christmas and I’d love to integrate it into Home Assistant. I’m definitely going to poke around in the code and see if I can see what’s what.

Could you explain the “Aerogarden static vars?” Where do you get that url from? Is it the same for each Aerogarden?

Also, the code posted here is commented, but the code on git-hub is not. Which is the more up to date version?

Hey roofuskit, I’m also looking to play around with this. I’ve modified some hass components before but never made a new one. I’d be happy to help with this as well. I’m guessing that the headers got copied over from wiresharking or otherwise tracking the traffic being sent to/from the app.

It’d be interesting to intercept the on/off commands as well, and then put the light in as a switch.

Just got one of these today, can’t wait to set it up at home. I have plenty of coding experience (though not as much with Python) but @epotex I’ll fork your repo and play with it. I’d love to see it running on HASS as well :smiley:

Cool, I’m excited, can’t wait to see it working and learn what i was missing! Good luck!

Guys, I’m in for a Aerogarden component! In fact, this summer, I want to set up a greenhouse and have everything setup in HA. If you need tester, I can. I’m not a programmer thought

Using @epotex code as a starting point I have a working home assistant component. It currently pulls data into sensor and binary_sensors.

You can find the code and documentation here:

I’d really like to turn the light into a switch so it can be toggled via home assistant too. I figured out the status API requests from the code posted by epotex, but has anyone figured out the exact api endpoint / arguments for turning the light on/off?

I have 2 harvest wifi units, and my component does support multiple gardens per account. I think it will work with all the other models but not 100% sure since I don’t have them to test.

I’d appreciate any feedback and testing by other AeroGarden users.

I’m glad to see that you got it to work, I’ll check your code later to figure out what I missed. :smiley:

Hey there. I was excited to find this thread/custom component. I just bought my wife a Harvest Elite WiFi for Christmas. Jut wanted to check to see if this component is still working, as it hasn’t been updated in a while.

Hope the answer is yes, and if so, glad to offer some testing. I don’t have any coding skills, but can help identify issues.

Hey @mikeg1130, I was able to @ksheumaker’s code work, just had to change a few lines in custom_components/aerogarden.py

If you’re running the latest version of HASS, change lines 179 - 181 to:

load_platform(hass, 'sensor', DOMAIN, {}, config)
load_platform(hass, 'binary_sensor', DOMAIN, {}, config)
load_platform(hass, 'light', DOMAIN, {}, config)

Anyone discover the endpoints for controlling the light turning on and off?

Thanks XeoSpeed. with your modifications, I was able to get it up and running. Very nice to have this integrated!

As for the light on/off, I am able to control the light via HA with ksheumaker’s component, but, as he notes, it is a little clunky. It works, but the UI switch flips back to on. I think this is because the status is only queried every 30 seconds. Maybe this is what the endpoints is meant to address?