Results 1 to 15 of 15

Thread: Give us an API

  1. #1
    New User
    Join Date
    Jan 2017
    Location
    Vienna
    Posts
    1

    Give us an API

    Dear Neptune Team.

    i dont know if i am the only one who is sad about Apex Fusion as it is a closed system.

    With the hype of smart home most things are controllable through an app.
    But we dont want 10 different APPs to controll our envirement.
    Most of the vendors providing APIs to access and controll it from a central installation like node red or iobroker.
    But to have it in such installation we need an API or at least an MQTT service in Fusion.

    what are other users thinking?

    LG Fey

  2. #2
    New User
    Join Date
    Nov 2018
    Location
    Norcal
    Posts
    11
    Yes, I would like to have an API as well. There are few use cases I can think of:
    - Export data to Grafana or other dashboards
    - Setup custom alerting based on parameters also outside the home (CO2 monitor for example)
    - Ability to react to tank events with means outside of the Apex ecosystem. For example, turn on A/C (Via Nest/Ecobee) if temp>79 && heater==off
    - Create my own Alexa/Google voice commands
    - Etc...

  3. #3
    Regular Vistor
    Join Date
    Oct 2015
    Location
    yardley, pa
    Posts
    24
    Ebnewbie, I think you can export xml data from the apex itself.

  4. #4
    New User
    Join Date
    Dec 2017
    Location
    CST
    Posts
    4
    I'm on the same page as the other posts. Ebnewbie is spot on. I would like real time tracking. Manually exporting a xml data file is a pain. More fun to develop cool new stuff anyway. Can the API allow me to trigger actions on the Apex?

  5. #5
    Regular Vistor
    Join Date
    Oct 2015
    Location
    yardley, pa
    Posts
    24
    william1034 I'm not sure how on one hand you can say "Manually exporting a xml data file is a pain" and on the other hand say "More fun to develop cool new stuff anyway". The data is in the xml you can "develop" a way to parse it.

  6. #6
    New User
    Join Date
    Dec 2017
    Location
    CST
    Posts
    4
    Parsing the XML is trivial. I would very much 'like' to have the open IoTa API they are talking about. Configuring a Raspberry PI with the necessary sensors and realtime monitoring could be a lot of fun to do. Do you have a link to the API?

  7. #7
    Master Control Freak RussM's Avatar
    Join Date
    Dec 2012
    Location
    California - US Pacific
    Posts
    17,719
    Quote Originally Posted by william1034 View Post
    Parsing the XML is trivial. I would very much 'like' to have the open IoTa API they are talking about. Configuring a Raspberry PI with the necessary sensors and realtime monitoring could be a lot of fun to do. Do you have a link to the API?
    There is no public API to download.

    The IoTa specification and API are not “open” or available to end users, nor is it a general-purpose API. It is a platform for collaborative effort between Neptune Systems and other aquarium equipment manufactures to enable control of 3rd-party equipment with the Apex.
    I'm not a Neptune support rep. Please do not send me PMs with technical questions or requesting assistance - use the forums for Apex help. PM me ONLY if the matter is of a private or personal nature. Thanks.

  8. #8
    Regular Vistor
    Join Date
    Oct 2015
    Location
    yardley, pa
    Posts
    24
    I shouldn't do this, but when i had the aquacontroller iii i had found out how to send commands with the
    web interface of the aqiii. I was actually using the http calls to write my own version of apex fusion
    since the aqiii did't work with fusion, and i wasn't ready to upgrade with to what is now the apex classic.
    Apparently the some urls still work with the apex classic and the apex 2016.



    to turn on off auto an outlet i tried these three and they worked


    http://APEXIPADDRESS:PORT/cgi-bin/st...CENAME_state=1 would turn the outlet called DEVICENAME OFF
    http://APEXIPADDRESS:PORT/cgi-bin/st...CENAME_state=0 would turn the outlet called DEVICENAME to AUTO
    http://APEXIPADDRESS:PORT/cgi-bin/st...CENAME_state=2 would turn the outlet called DEVICENAME ON


    I you put that in your browser it will popup a username and password screen, but programatically in an .asp
    you could do


    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "POST", "http://APEXIPADDRESS:PORT/cgi-bin/status.cgi?DEVICENAME_state=2", FALSE, "apex username","apex password"
    objHTTP.Send




    you also still have http://APEXIPADDRESS:PORT/cgi-bin/datalog.xml to get data in xml to parse.


    you also have the rss feed http://APEXIPADDRESS:PORT/rss.sht


    and http://APEXIPADDRESS:PORT/cgi-bin/outlog.xml


    and http://APEXIPADDRESS:PORT/cgi-bin/program.xml


    I think there was a url to update the clock too and it would reset the data log. So i would programatically retrive
    the datalog every day at 00:01am set the clock to wipe out the datalog and then imported the retrived data into mysql.


    when i got the apex classic i abandonded this but here is the asp class i wrote. I have no idea how much of it works though.
    i would not play with this on a live system and do it at your own risk.




    ----------begin asp----------
    IP="192.168.1.27:80"
    URL="http://192.168.1.27:80"


    '----------------------------------------------------------
    ' STATUS FUNCTIONS
    '----------------------------------------------------------


    Class AQ3_STATUS
    private Buffer

    Private Sub Class_Initialize
    Buffer=GET_STATUS_BUFFER
    End Sub

    Private Sub Class_Terminate
    ' Statements go here.
    End Sub


    public function GET_STATUS_BUFFER
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "GET", URL&"/cgi-bin/status.xml", FALSE, "admin","1234"
    objHTTP.Send
    Buffer=objHTTP.ResponseText
    GET_STATUS_BUFFER=Buffer
    end function


    public function GET_TEMP
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("probe")
    For i = 0 To (objNodeList.length - 1)
    if instr(objNodeList.Item(i).text,"Temp") then
    strng=strng&objNodeList.Item(i).text
    end if
    Next
    GET_TEMP=split(strng," ")(1)
    end function


    public function GET_PH
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("probe")
    For i = 0 To (objNodeList.length - 1)
    if instr(objNodeList.Item(i).text,"pH") then
    strng=strng&objNodeList.Item(i).text
    end if
    Next
    GET_PH=split(strng," ")(1)
    end function


    public function GET_ORP
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("probe")
    For i = 0 To (objNodeList.length - 1)
    if instr(objNodeList.Item(i).text,"ORP") then
    strng=strng&objNodeList.Item(i).text
    end if
    Next
    GET_ORP=split(strng," ")(1)
    end function


    public function GET_TIME
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("date")
    strng=strng&objNodeList.Item(i).text
    GET_TIME=strng
    end function


    public function GET_DEVICE_LIST
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("outlet")
    For i = 0 To (objNodeList.length - 1)
    if i>0 then strng=strng&"|"
    if left(split(objNodeList.Item(i).text," ")(2),1)="A" then
    if split(objNodeList.Item(i).text," ")(2)="AON" then
    strng=strng&split(objNodeList.Item(i).text," ")(0)&" is ON Auto"
    else
    strng=strng&split(objNodeList.Item(i).text," ")(0)&" is OFF Auto"
    end if
    else
    strng=strng&split(objNodeList.Item(i).text," ")(0)&" is "&split(objNodeList.Item(i).text," ")(2)&" Manual"
    end if
    Next
    GET_DEVICE_LIST=strng
    end function


    public function GET_DEVICE_STATUS(fDeviceName)
    records=split(GET_DEVICE_LIST,"|")
    for i=0 to ubound(records)
    if split(records(i)," ")(0)=fDeviceName then
    GET_DEVICE_STATUS=split(records(i)," ")(2)
    Exit For
    end if
    next
    end function


    public function GET_DEVICE_CONTROL_STATUS(fDeviceName)
    records=split(GET_DEVICE_LIST,"|")
    for i=0 to ubound(records)
    if split(records(i)," ")(0)=fDeviceName then
    GET_DEVICE_CONTROL_STATUS=split(records(i)," ")(3)
    Exit For
    end if
    next
    end function


    public function GET_POWER_FAILED
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("failed")
    strng=strng&objNodeList.Item(i).text
    GET_POWER_FAILED=strng
    end function


    public function GET_POWER_RESTORED
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("restored")
    strng=strng&objNodeList.Item(i).text
    GET_POWER_RESTORED=strng
    end function


    public function GET_DEVICE_NAME(fDevice)
    GET_DEVICE_NAME=fDevice
    select case fDevice
    case "LT1"
    GET_DEVICE_NAME="FRONT LIGHTS"
    case "LT2"
    GET_DEVICE_NAME="BACK LIGHTS"
    case "MNL"
    GET_DEVICE_NAME="MOON LIGHT"
    case "PM1"
    GET_DEVICE_NAME="WAVE SURGE"
    case "ALM"
    GET_DEVICE_NAME="ALARM"
    end select
    end function


    end class




    '----------------------------------------------------------------
    ' DATALOG FUNCTIONS
    '----------------------------------------------------------------
    Class AQ3_DATA_LOG
    private Buffer
    Private Sub Class_Initialize
    Buffer=GET_LOG_BUFFER
    End Sub

    Private Sub Class_Terminate
    ' Statements go here.
    End Sub

    public function GET_LOG_BUFFER
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "GET", URL&"/cgi-bin/datalog.xml", FALSE, "admin","1234"
    objHTTP.Send
    Buffer=objHTTP.ResponseText
    GET_LOG_BUFFER=Buffer
    end function


    public function RESET_DATA_LOG
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "GET", URL&"/cgi-bin/clock.cgi?tankTime="&monthname(month(date))&" "&day(date)&" "&year(date)&" "&hour(time)&":"&minute(time)&":"&second(time) , FALSE, "admin","1234"
    objHTTP.Send
    RESET_DATA_LOG=objHTTP.ResponseText
    end function


    public function GET_DATA_LOG(fReset)
    Set xmlDoc = CreateObject("Msxml2.DOMDocument")
    xmlDoc.loadXML Buffer
    Set objNodeList = xmlDoc.getElementsByTagName("record")
    For i = 0 To (objNodeList.length - 1)
    if i>0 then strng=strng&"|" end if
    strng=strng&replace(replace(replace(objNodeList.It em(i).text,"Temp",""),"pH",""),"ORP","")
    Next
    if fReset then
    RESET_DATA_LOG
    end if
    GET_DATA_LOG=strng
    end function


    end class


    '----------------------------------------------------------------
    ' PROGRAM FUNCTIONS
    '----------------------------------------------------------------
    Class AQ3_PROGRAM
    private Buffer
    Private Sub Class_Initialize
    GET_PROGRAM_BUFFER
    End Sub

    Private Sub Class_Terminate
    ' Statements go here.
    End Sub


    public function GET_PROGRAM_BUFFER
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "GET", URL&"/cgi-bin/program.cgi", FALSE, "admin","1234"
    objHTTP.Send
    Buffer=objHTTP.ResponseText
    GET_PROGRAM_BUFFER=Buffer
    end function


    public function GET_DEVICE_X10_LIST
    temp=Buffer
    temp2=mid(temp, instr(temp,"<textarea class=""tbflat"" name=""timer"" cols=""50"" rows =""15"">"))
    temp3=mid(temp2,1,instr(temp2,"</textarea>")-1)
    temp3=replace(replace(temp3,"<textarea class=""tbflat"" name=""timer"" cols=""50"" rows =""15"">",""),vblf&vblf,"")
    GET_DEVICE_X10_LIST=replace(left(temp3,len(temp3)-1),vblf,"|")
    end function


    public function GET_DEVICE_X10(fDevice)
    records=split(GET_DEVICE_X10_LIST,"|")
    for i=0 to ubound(records)
    if(left(split(records(i),"-")(0),3)=fDevice) then
    response.write split(records(i),"-")(1)
    end if
    next
    end function


    public function GET_PROGRAM
    temp=Buffer
    temp2=mid(temp, instr(temp,"<textarea class=""tbflat"" name=""program"" cols=""95"" rows =""15"">"))
    temp3=mid(temp2,1,instr(temp2,"</textarea>")-1)
    temp3=rtrim(replace(temp3,"<textarea class=""tbflat"" name=""program"" cols=""95"" rows =""15"">",""))
    GET_PROGRAM=replace(temp3,vblf,"|")
    end function


    end class
    '----------------------------------------------------------------
    ' SUN/MOON FUNCTIONS
    '----------------------------------------------------------------


    Class AQ3_SUNMOON
    private Buffer
    Private Sub Class_Initialize
    End Sub

    Private Sub Class_Terminate
    End Sub

    public function GET_SUN_MOON_BUFFER
    'GET_SUN_MOON_DATA(0)
    end function


    public function GET_SUN_MOON_DATA(fMonth)
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "POST", URL&"/cgi-bin/season.cgi?Refresh=Refresh&month="&fMonth, FALSE, "admin","1234"
    objHTTP.Send
    temp=left(objHTTP.ResponseText,instr(objHTTP.Respo nseText,"</TABLE>")-1)
    Buffer=right(temp,len(temp)-instr(temp,"Temperature</TD></TR>")-20)
    Buffer=replace(replace(replace(replace(Buffer,"</TD><TD class=""smallertext"">",","),"<TR><TD class=""smallertext"">","|"),"</TD></TR>",""),"/",",")
    Buffer=right(Buffer,len(Buffer)-1)
    GET_SUN_MOON_DATA=Buffer
    end function


    public function GET_SUN_MOON_DATA_DATE(fDate)
    GET_SUN_MOON_DATA_DATE=""
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "POST", URL&"/cgi-bin/season.cgi?Refresh=Refresh&month="&month(fDate)-1, FALSE, "admin","1234"
    objHTTP.Send
    temp=left(objHTTP.ResponseText,instr(objHTTP.Respo nseText,"</TABLE>")-1)
    Buffer=right(temp,len(temp)-instr(temp,"Temperature</TD></TR>")-20)
    Buffer=replace(replace(replace(replace(Buffer,"</TD><TD class=""smallertext"">",","),"<TR><TD class=""smallertext"">","|"),"</TD></TR>",""),"/",",")
    Buffer=right(Buffer,len(Buffer)-1)
    records=split(Buffer,"|")
    for i=0 to ubound(records)
    if cint(split(split(records(i),",")(0)," ")(1))=day(fdate) then
    GET_SUN_MOON_DATA_DATE=records(i)
    end if
    next
    'GET_SUN_MOON_DATA_DATE=Buffer
    end function

    end class


    '----------------------------------------------------------------
    ' DEVICE CONTROL FUNCTIONS
    '----------------------------------------------------------------


    public function DEVICE_COMMAND(fDevice, fCommand)
    end function


    public function DEVICE_ON(fDevice) '2=on
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "POST", URL&"/cgi-bin/status.cgi?"&fDevice&"_state=2", FALSE, "admin","1234"
    objHTTP.Send
    Buffer=objHTTP.ResponseText
    DEVICE_ON=Buffer
    end function


    public function DEVICE_OFF(fDevice) '1=off
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "POST", URL&"/cgi-bin/status.cgi?"&fDevice&"_state=1", FALSE, "admin","1234"
    objHTTP.Send
    Buffer=objHTTP.ResponseText
    DEVICE_OFF=Buffer
    end function


    public function DEVICE_AUTO(fDevice) '0=auto
    set objHTTP = CreateObject("MSXML2.XMLHTTP")
    objHTTP.Open "POST", URL&"/cgi-bin/status.cgi?"&fDevice&"_state=0", FALSE, "admin","1234"
    objHTTP.Send
    Buffer=objHTTP.ResponseText
    DEVICE_AUTO=Buffer
    end function



    ---end asp-------

  9. #9
    Regular Vistor
    Join Date
    Oct 2015
    Location
    yardley, pa
    Posts
    24
    This was as far as i got creating my own web page with it. The 7 day numbers are blank because i haven't imported data since i got the apex classic.

    Do the on off auto buttons look familiar? Clicking the buttons would turn the outlet on off or auto.

    aq.jpg

  10. #10
    New User
    Join Date
    Nov 2018
    Location
    Norcal
    Posts
    11
    Nice script.
    Unfortunately for me, I'm a bit too chicken to use a web scraper to control life support equipment. I'm a software engineer and it's not the technical challenge that shies me away but the lack of guarantee and stability of this method.
    I think I'll start with the telegraf input plugin described in my other thread. I wish Neptune would offer a simple API. Their JS-based fusion frontend calls an /api so if you're going to scrape, that method might be best.

  11. #11
    Regular Vistor
    Join Date
    Oct 2015
    Location
    yardley, pa
    Posts
    24
    Well, Russ said you're not getting an API so you're going to have to figure out another way. What exactly are you trying to do? Because i gave you the urls to to get all the data as xml so you can get all the info you would need. The only other piece is turning devices on and off and i gave you the urls to do that. As a software engineer with that info you should be able to do all kinds of stuff, and while yes some of my script was web scrapping the xml urls are really data sets. BTW: he on off urls look like they got shortend and should be:

    /cgi-bin/status.cgi?DEVICENAME_state=0
    /cgi-bin/status.cgi?DEVICENAME_state=1
    /cgi-bin/status.cgi?DEVICENAME_state=2

  12. #12
    Master Control Freak RussM's Avatar
    Join Date
    Dec 2012
    Location
    California - US Pacific
    Posts
    17,719
    Quote Originally Posted by Ebnewbie View Post
    Unfortunately for me, I'm a bit too chicken to use a web scraper to control life support equipment. I'm a software engineer and it's not the technical challenge that shies me away but the lack of guarantee and stability of this method.
    Well said. I feel the same way. I too can do it, but won't... too much risk of something changing in a firmware update, for example, causing unexpected - or detrimental - things to happen.

    Now, putting on my forum staff hat... Using the XML from the Apex is the only form of machine interface which is provided by Neptune and is open to discussion. This thread is going in a direction that is disallowed by forum rules and policies, because doing such things requires reverse engineering, and discussion of that is not allowed here (https://forum.neptunesystems.com/sho...s-and-Policies). Let's not continue down that path....

    Their JS-based fusion frontend calls an /api so if you're going to scrape, that method might be best.
    The APEX Fusion terms of use prohibit such activity.
    I'm not a Neptune support rep. Please do not send me PMs with technical questions or requesting assistance - use the forums for Apex help. PM me ONLY if the matter is of a private or personal nature. Thanks.

  13. #13
    Regular Vistor
    Join Date
    Oct 2015
    Location
    yardley, pa
    Posts
    24
    Sorry if i was violating any rules, but to borrow a line from gene kranz "i don't care what it was designed to do. I wan to know what it can do."

  14. #14
    New User
    Join Date
    Nov 2018
    Location
    Norcal
    Posts
    11
    Thanks for the reply Russ, I'm new here so didn't know that discussing "off the beaten path" uses of the Apex was prohibited.
    Since your have your staff hat on (I didn't even know you were a Neptune employee because of your signature lol), can you let us know if the lack of API is driven by a technical hurdle (Lack or time, engineering resources) or by a commercial vision (Licensing fees for "Works with Apex", only licensed devices can work wit

  15. #15
    Frequent Visitor bigjim's Avatar
    Join Date
    Oct 2014
    Location
    Carpentersville, Il
    Posts
    378
    Quote Originally Posted by etpelle View Post
    Sorry if i was violating any rules
    As they say... "Better to ask for forgiveness then to ask for permission".

Bookmarks

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •