Jump to content

Welcome to Smart Home Forum by FIBARO

Dear Guest,

 

as you can notice parts of Smart Home Forum by FIBARO is not available for you. You have to register in order to view all content and post in our community. Don't worry! Registration is a simple free process that requires minimal information for you to sign up. Become a part of of Smart Home Forum by FIBARO by creating an account.

 

As a member you can:

  •     Start new topics and reply to others
  •     Follow topics and users to get email updates
  •     Get your own profile page and make new friends
  •     Send personal messages
  •     ... and learn a lot about our system!

 

Regards,

Smart Home Forum by FIBARO Team


  • 0

Question

Posted

I want to stop Nilan when my extractor hood is Running, to ensure right airflow in the house - and a lot more great usecases.

 

For my Nilan Ventilation I have builded a small converter based on ESP8266 to convert the Modbus to HTTP or MQTT

Nilan Modbus firmware for D1 Mini (ESP8266) together with a TTL to RS485 Converter

Please login or register to see this link.


 

Its two way communication with the Nilan

 

Getting values by HTTP:
You can get some json values from the Nilan by calling to it via HTTP. Just use your browser and type:

DEVICE - corresponds to the IP adress you you device (esp8266)

http://[device]/help - This should give you som registers

http://[device]/read/output - This would for example give you some status of the output

http://[device]/set/[group]/[adress]/[value]- This would make you able to send commands through HTTP

 

 

Getting values by MQTT:

Any MQTT-Tool :

ventilation/temp/#- This will give the temperatures from all the sensors.

ventilation/moist/#- This will give the humidity from the systems humidity sensor.

ventilation/# - This gives the output of the system - fan speed etc. Remember the payloads are given in values not text.

It based on a whole teams work in denmark, and everything its collected here.

Please login or register to see this link.

 

There are

  • 4 temperature sensors
  • 1 Humidity Sensor
  • 1 sensor for Fan Speed
  • 1 sensor for Bypass (How much indoor and outdoor air is blended)
  • 1 switch for user Program selection (can be On/Off) and select a Setting program in Nilan
  • 1 sensor for Filter - indicating if Filter need to change.

 

Anyone else having Nilan or Genvex or already started on an Integration like this?

the way @jgab is working with QA Childs is just really amazing - I'm having a steep learning curve, and dont master the technique yet :( 

So looking for allies

If I have the Base QA and one working Sensor, I can manage to ADD the rest myself.

 

1311666616_NilanSensors.jpg.232a5205560a4eecc791b83d81476dd2.jpg

 

 

 

20 answers to this question

Recommended Posts

  • 0
Posted
46 minutes ago, ChristianSogaard said:

There are

  • 4 temperature sensors
  • 1 Humidity Sensor
  • 1 sensor for Fan Speed
  • 1 sensor for Bypass (How much indoor and outdoor air is blended)
  • 1 switch for user Program selection (can be On/Off) and select a Setting program in Nilan
  • 1 sensor for Filter - indicating if Filter need to change.

 

Design wise you can make one QA that have controls/labels for all the values.

The advantage is that you keep it all in one QA with one UI.

The disadvantage is that it's a bit of a hassle to read values out of the QA. Devices don't have so many properties to store values in. This makes it a bit cumbersome to make block scenes that trigger on the QA.

 

The other alternative is to split it into a main device and children for each sensor/switch.

Makes it easy to trigger on value changes but you end up with 1+9 devices.

  • 0
  • Inquirer
  • Posted
    6 minutes ago, jgab said:

     

    Design wise you can make one QA that have controls/labels for all the values.

    The advantage is that you keep it all in one QA with one UI.

    The disadvantage is that it's a bit of a hassle to read values out of the QA. Devices don't have so many properties to store values in. This makes it a bit cumbersome to make block scenes that trigger on the QA.

     

    The other alternative is to split it into a main device and children for each sensor/switch.

    Makes it easy to trigger on value changes but you end up with 1+9 devices.

    Would you go for http or Mqtt integration? I think mqtt is probably the best because it’s easier to detect the changes in the sensors. But it’s only a hunch 

    • 0
    Posted
    1 minute ago, ChristianSogaard said:

    Would you go for http or Mqtt integration? I think mqtt is probably the best because it’s easier to detect the changes in the sensors. But it’s only a hunch 

    I have not used the MQTT client that much on the HC3. I think I read some reports on "instability", like

    The advantage is that you get the new values pushed to you and with http you need to poll. (but inside the MQTT client there is someone polling a socket anyway...)

    ...so I would have started with http - less things that can go wrong ;-)

     

     

    • 0
  • Inquirer
  • Posted (edited)
    On 11/9/2020 at 8:59 PM, ChristianSogaard said:

    I want to stop Nilan when my extractor hood is Running, to ensure right airflow in the house - and a lot more great usecases.

     

    For my Nilan Ventilation I have builded a small converter based on ESP8266 to convert the Modbus to HTTP or MQTT

    Nilan Modbus firmware for D1 Mini (ESP8266) together with a TTL to RS485 Converter

    Please login or register to see this link.


     

    Its two way communication with the Nilan

     

    Getting values by HTTP:
    You can get some json values from the Nilan by calling to it via HTTP. Just use your browser and type:

    DEVICE - corresponds to the IP adress you you device (esp8266)

    http://[device]/help - This should give you som registers

    http://[device]/read/output - This would for example give you some status of the output

    http://[device]/set/[group]/[adress]/[value]- This would make you able to send commands through HTTP

     

     

    Getting values by MQTT:

    Any MQTT-Tool :

    ventilation/temp/#- This will give the temperatures from all the sensors.

    ventilation/moist/#- This will give the humidity from the systems humidity sensor.

    ventilation/# - This gives the output of the system - fan speed etc. Remember the payloads are given in values not text.

    It based on a whole teams work in denmark, and everything its collected here.

    Please login or register to see this link.

     

    There are

    • 4 temperature sensors
    • 1 Humidity Sensor
    • 1 sensor for Fan Speed
    • 1 sensor for Bypass (How much indoor and outdoor air is blended)
    • 1 switch for user Program selection (can be On/Off) and select a Setting program in Nilan
    • 1 sensor for Filter - indicating if Filter need to change.

     

    Anyone else having Nilan or Genvex or already started on an Integration like this?

    the way @jgab is working with QA Childs is just really amazing - I'm having a steep learning curve, and dont master the technique yet :( 

    So looking for allies

    If I have the Base QA and one working Sensor, I can manage to ADD the rest myself.

     

    Please login or register to see this link.

     

     

     

    I start getting in Data in Nilan QA - thank you to @jgab and @laurgh for sharing code for inspiration and re-use

     

     

    image.png.807e45d20d5531dd51f4544e1f9b516d.png

     

     

    Calling this URL  http://192.168.201.19/read/temp 

    returning 

    Please login or register to see this code.

     

    I am using this code to read the json

    Please login or register to see this code.

     

    I need to read following

    1.    http://192.168.201.19/read/control

    2.   http://192.168.201.19/read/temp

    3.   http://192.168.201.19/read/info

    4.   http://192.168.201.19/read/inputairtemp

     

    Instead of having the function four times - how to i change i to have input parameter (control, temp, info, inputairtemp) and return a variable like control_data = json.decode(response.data) ?

     

     

     

     

    Please login or register to see this attachment.

     

    Edited by ChristianSogaard
    • 0
  • Inquirer
  • Posted (edited)

    Hi @jgab @10derand all you other great experts

     

    I trying to use ZeroBrane with your Plugin - first real project.

    This is what i have for now - I had i working but wanted to do changes to the UI, and there is some things i dont understrand.

    Please login or register to see this attachment.

     

     

    When do I use the QuickApp in the function ? - because i have seen QA where QuickApp is not listes in the function deceleration  

    Please login or register to see this code.

     

    Second

    in the attached QA - i'm getting in ZBS

     

    [04.12.2020] [17:48:29] [[31;1mERROR[0m]: "invalid host ''"
    [04.12.2020] [17:48:29] [[31;1mERROR[0m]: "invalid host ''"

     

    same error, but from HC3 site

    [04.12.2020] [17:24:04] [ERROR] [QUICKAPP970]: "Bad file descriptor"
    [04.12.2020] [17:24:04] [ERROR] [QUICKAPP970]: "Bad file descriptor"

     

    when the   dofile("fibaroapiHC3.lua") is called.

    not sure if its my core or something i didnt configure right in ZBS

    Please login or register to see this attachment.

    Edited by ChristianSogaard
    • 0
    Posted (edited)

    Hi,

    Invalid host and bad file descriptor you get because your address (ip) is in a bad format or "".

    You can set the quickAppVariables that the QA should have at startup in the header like this

    Please login or register to see this code.

     

    There was something strange with 'btnFANPressed2' listed twice in the UI sections.

    Btw, when defining a button it's best to define the 'onReleased' key. It specifies the name of the button call back function. If it's not given the SDK needs to guess and it often becomes "on"..<buttonID>. See my attached code.

     

    So QuickApp is a class (object oriented programming). Fibaro provides a lot of functions in that class (ex. :updateView(...) )

    You can extend that class with your own functions (like :refreshControlInfo() )

    When your code starts up an instance of the class is created and its :onInit() function is called.

    You refer to the instance with the variable 'self', like self:refreshControlInfo(response)

    'self' is only available inside class functions.

     

    If you declare a function without QuickApp: it's a "normal" Lua function and it does not have access to 'self' so it can't call self:debug(...) etc.

    However, it turns out that when the QuickApp instance is created, it also assigns the global variable quickApp the instance, so you can do

    Please login or register to see this code.

     

    Why not declare all functions as methods on the QuickApp class?

    Well, first all QuickApp functions are accessible from other QAs by calling fibaro.call(<QA ID>,<function name>, <arguments>)

    or via the http REST api...   so it's kind of a public API

    Secondly, it can be nice to have locally scoped Lua functions...

     

    I fixed some small bugs and made some (unnecessary) changes to your code.

    Please login or register to see this attachment.

     

    - I factored out a getHTTPinfo function used to poll data from the device. QuickApp:refreshControlInfo() makes a setInterval loop calling getHTTPinfo and provides a callback function that does self:onControlInfoRecieved.

    Same for the other loop.

     

    -I made a version of formatting the label with colors. If you use string.format you can control the formatting of decimal numbers. In my example I format to 2 decimals. It's still not very pretty in the QA UI but you know better how you want it.

     

    -I made a table of status codes instead of if-then-else-... It's a standard Lua idiom for that kind of things...

     

    I did not go into details of the logic of your QA, but I'm happy to discuss it as it progress... (the child updating code looks a bit strange...)

    Keep on coding.

    Edited by jgab
    Fixed bug...
    • Like 1
    • 0
  • Inquirer
  • Posted
    2 hours ago, jgab said:

    Hi,

    Invalid host and bad file descriptor you get because your address (ip) is in a bad format or "".

    You can set the quickAppVariables that the QA should have at startup in the header like this

    Please login or register to see this code.

     

    There was something strange with 'btnFANPressed2' listed twice in the UI sections.

    Btw, when defining a button it's best to define the 'onReleased' key. It specifies the name of the button call back function. If it's not given the SDK needs to guess and it often becomes "on"..<buttonID>. See my attached code.

     

    So QuickApp is a class (object oriented programming). Fibaro provides a lot of functions in that class (ex. :updateView(...) )

    You can extend that class with your own functions (like :refreshControlInfo() )

    When your code starts up an instance of the class is created and its :onInit() function is called.

    You refer to the instance with the variable 'self', like self:refreshControlInfo(response)

    'self' is only available inside class functions.

     

    If you declare a function without QuickApp: it's a "normal" Lua function and it does not have access to 'self' so it can't call self:debug(...) etc.

    However, it turns out that when the QuickApp instance is created, it also assigns the global variable quickApp the instance, so you can do

    Please login or register to see this code.

     

    Why not declare all functions as methods on the QuickApp class?

    Well, first all QuickApp functions are accessible from other QAs by calling fibaro.call(<QA ID>,<function name>, <arguments>)

    or via the http REST api...   so it's kind of a public API

    Secondly, it can be nice to have locally scoped Lua functions...

     

    I fixed some small bugs and made some (unnecessary) changes to your code.

    Please login or register to see this attachment.

     

    - I factored out a getHTTPinfo function used to poll data from the device. QuickApp:refreshControlInfo() makes a setInterval loop calling getHTTPinfo and provides a callback function that does self:onControlInfoRecieved.

    Same for the other loop.

     

    -I made a version of formatting the label with colors. If you use string.format you can control the formatting of decimal numbers. In my example I format to 2 decimals. It's still not very pretty in the QA UI but you know better how you want it.

     

    -I made a table of status codes instead of if-then-else-... It's a standard Lua idiom for that kind of things...

     

    I did not go into details of the logic of your QA, but I'm happy to discuss it as it progress... (the child updating code looks a bit strange...)

    Keep on coding.

    I like what i learn. :-) The table status is brilliant.

    For the logic of the QA - I have the functions refreshControlInfoOnce and refreshSensorInfo

    I want to have 5 of those - local URLaddress = 'http://'..ip..'/read/

    • Control
    • Output 
    • temp
    • info
    • inputairtemp

    but i think 5 functions is bad to maintain and I'm fearing timing issues when then auto refresh triggers - if two read request is done almost same time when modbus is not finished reading.

    so  it might be better having a master function calling refreshSensorInfo with the different 5 parameters in sequence  ?

    • 0
    Posted
    2 minutes ago, ChristianSogaard said:

    I like what i learn. :-) The table status is brilliant.

    For the logic of the QA - I have the functions refreshControlInfoOnce and refreshSensorInfo

    I want to have 5 of those - local URLaddress = 'http://'..ip..'/read/

    • Control
    • Output 
    • temp
    • info
    • inputairtemp

    but i think 5 functions is bad to maintain and I'm fearing timing issues when then auto refresh triggers - if two read request is done almost same time when modbus is not finished reading.

    so  it might be better having a master function calling refreshSensorInfo with the different 5 parameters in sequence  ?

    Does all sensors have different IP addresses?

    I would expect URLaddress = 'http://'..ip..'/read/temp'

    to get a list of all temp sensors or?

    • 0
  • Inquirer
  • Posted (edited)
    7 minutes ago, jgab said:

    Does all sensors have different IP addresses?

    I would expect URLaddress = 'http://'..ip..'/read/temp'

    to get a list of all temp sensors or?

    No - its the same IP - but i need to read 5 times to get all the data i need (actually i dont need it now - but want to prepare for later use)

    • http://'..ip..'/read/Control
    • http://'..ip..'/read/Output
    • http://'..ip..'/read/temp
    • http://'..ip..'/read/info
    • http://'..ip..'/read/inputairtemp


     
     

    Please login or register to see this code.

     

    Edited by ChristianSogaard
    • 0
    Posted (edited)
    22 minutes ago, ChristianSogaard said:

    No - its the same IP - but i need to read 5 times to get all the data i need (actually i dont need it now - but want to prepare for later use)

    • http://'..ip..'/read/Control
    • http://'..ip..'/read/Output
    • http://'..ip..'/read/temp
    • http://'..ip..'/read/info
    • http://'..ip..'/read/inputairtemp

     

    Ok, I understand. It would have been elegant if http://'..ip..'/read    would have returned all sensors.

    I would loop each sensor. Can it take a request / second?

    Please login or register to see this code.

     

    If it has a hard time coping with 1s requests you may need to structure the code differently...

    Edited by jgab
    Bug mixing up self & resp
    • Like 1
    • 0
  • Inquirer
  • Posted
    35 minutes ago, jgab said:

     

    Ok, I understand. It would have been elegant if http://'..ip..'/read    would have returned all sensors.

    I would loop each sensor. Can it take a request / second?

    Please login or register to see this code.

     

    If it has a hard time coping with 1s requests you may need to structure the code differently...

    This line ( sIndex = (sIndex % #sensors)+1   --- wrap around index)

    that is (sIndex=sIndex+1 and select the next in sensors {} ?  - i get the meaning i´m pretty sure

     

    For the "         getHTTPinfo('http://'..ip..'/read/'..sensor.name, sensor.callback)"

    the sensor.callback eg  contains "function(resp) quickApp:airTemp(resp) end" - I'm not understanding  - is that instead of the refreshControlInfoOnce ?

     

    I think this way might limit me - if I PUSH a button - the registres will be written - and I want to read right after to update the UI. So the Poll sensors should also be able to handle a input parameter like "{name='Control'], callback = function(resp) quickApp:handleControl(resp) end}"

     

    1 second between the each register reading is fint - i think having 60 sec between each loop should be fine :-)

     

    • 0
    Posted (edited)
    23 minutes ago, ChristianSogaard said:

    This line ( sIndex = (sIndex % #sensors)+1   --- wrap around index)

    that is (sIndex=sIndex+1 and select the next in sensors {} ?  - i get the meaning i´m pretty sure

     

    For the "         getHTTPinfo('http://'..ip..'/read/'..sensor.name, sensor.callback)"

    the sensor.callback eg  contains "function(resp) quickApp:airTemp(resp) end" - I'm not understanding  - is that instead of the refreshControlInfoOnce ?

     

    I think this way might limit me - if I PUSH a button - the registres will be written - and I want to read right after to update the UI. So the Poll sensors should also be able to handle a input parameter like "{name='Control'], callback = function(resp) quickApp:handleControl(resp) end}"

     

    1 second between the each register reading is fint - i think having 60 sec between each loop should be fine :-)

     

     

    Yes it creates the serie 1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,...

     

    Now it polls each second, all the time

     

    Please login or register to see this code.

     

    This modified so it you specify a delay to the next sensor to be polled, here we wait 55s until we poll the sensors again. You can mix and match delays as you want. You could spread the calls out evenly over the minute...

     

    I factored out a checkControlOnce() so that it can be called after you set a parameter.

     

    Yes, this replace the two setInterval loops in the old code.

     

    Edited by jgab
    • Like 1
    • 0
  • Inquirer
  • Posted
    5 hours ago, jgab said:

     

    Yes it creates the serie 1,2,3,4,5,1,2,3,4,5,1,2,3,4,5,...

     

    Now it polls each second, all the time

     

    Please login or register to see this code.

     

    This modified so it you specify a delay to the next sensor to be polled, here we wait 55s until we poll the sensors again. You can mix and match delays as you want. You could spread the calls out evenly over the minute...

     

    I factored out a checkControlOnce() so that it can be called after you set a parameter.

     

    Yes, this replace the two setInterval loops in the old code.

     

    I tried merging the code. :-)

    I'm getting - [05.12.2020] [16:56:00] |[31;1mERROR[0m|: QuickApp crashed: NilanQA.lua:163: attempt to call global 'getHTTPInfo' (a nil value)

    Line 163 is this section.

    getHTTPInfo - has both capital I and small i - this is changes to getHTTPInfo.

    a nil value - is empty right? - so sensor name or sencor callback is emptY?

     

    Please login or register to see this code.

     

    • 0
    Posted
    4 minutes ago, ChristianSogaard said:

    I tried merging the code. :-)

    I'm getting - [05.12.2020] [16:56:00] |[31;1mERROR[0m|: QuickApp crashed: NilanQA.lua:163: attempt to call global 'getHTTPInfo' (a nil value)

    Line 163 is this section.

    getHTTPInfo - has both capital I and small i - this is changes to getHTTPInfo.

    a nil value - is empty right? - so sensor name or sencor callback is emptY?

     

    Please login or register to see this code.

     

     

    Must have misspelled getHTTPInfo.

    I don't follow "a nil value - is empty right? - so sensor name or sencor callback is emptY?" - when is it nil?

    Maybe you can post the whole code again?

    • 0
  • Inquirer
  • Posted
    16 hours ago, jgab said:

     

    Must have misspelled getHTTPInfo.

    I don't follow "a nil value - is empty right? - so sensor name or sencor callback is emptY?" - when is it nil?

    Maybe you can post the whole code again?

     

    Please login or register to see this attachment.

    • 0
    Posted

    Please login or register to see this attachment.

     

    It was missing a self:  infront of getHTTPInfo...

    I moved around the functions a bit.

    I made:

    Please login or register to see this code.

     

    to get the various infos. It's cleaner that way. Those functions are also used in the table for the loop polling the sensors.

    checkControl()  can also be used from function QuickApp:SendControlInfo()

     

    I guess you need to rewrite QuickApp:SendControlInfo() to be able to send different types of commands?

    Something like a sendHTTPcommand(command) that can be used from from sendControlInfo()... etc.

     

    Oh, I forgot to comment the TEST variable in the beginning that I use to simulate responses. Comment that line.

     

    I also realise that I left a couple of

    Please login or register to see this code.

    structures in the code. I like to wrap sections of functions in do ... end because then I can easily fold that section in the ZBS editor (the little '+' sign in the left margin) - makes it easier to navigate the code.

    • Like 1
    • 0
  • Inquirer
  • Posted
    11 hours ago, jgab said:

    Please login or register to see this attachment.

     

    It was missing a self:  infront of getHTTPInfo...

    I moved around the functions a bit.

    I made:

    Please login or register to see this code.

     

    to get the various infos. It's cleaner that way. Those functions are also used in the table for the loop polling the sensors.

    checkControl()  can also be used from function QuickApp:SendControlInfo()

     

    I guess you need to rewrite QuickApp:SendControlInfo() to be able to send different types of commands?

    Something like a sendHTTPcommand(command) that can be used from from sendControlInfo()... etc.

     

    Oh, I forgot to comment the TEST variable in the beginning that I use to simulate responses. Comment that line.

     

    I also realise that I left a couple of

    Please login or register to see this code.

    structures in the code. I like to wrap sections of functions in do ... end because then I can easily fold that section in the ZBS editor (the little '+' sign in the left margin) - makes it easier to navigate the code.

    I tried figuring out why its not working (updating the GUI)

    this Code is being run successfully - i see the traces.

    Please login or register to see this code.

     

    But this function never runs

    Please login or register to see this code.

    at least - i dont see the "  self:trace("onControlInfoRecieved - Vi har læst i read/control")"  being put in the log.

    onControlInfoRecieved - is spelled identical 

     

     

    • 0
    Posted
    1 hour ago, ChristianSogaard said:

    I tried figuring out why its not working (updating the GUI)

    this Code is being run successfully - i see the traces.

    Please login or register to see this code.

     

    But this function never runs

    Please login or register to see this code.

    at least - i dont see the "  self:trace("onControlInfoRecieved - Vi har læst i read/control")"  being put in the log.

    onControlInfoRecieved - is spelled identical 

     

     

    Did you comment out the line around line ~34 ?

    Please login or register to see this code.

     

    • 0
  • Inquirer
  • Posted (edited)
    9 hours ago, jgab said:

    Did you comment out the line around line ~34 ?

    Please login or register to see this code.

     

    my bad - i did first, but overwrote when setting in new code ;-)

     

    I think i need to build in some error handling - when "Modbus connection failed", because the QuickApp crashed

     

    [07.12.2020] [08:58:00] [[33mTRACE[0m]: Response data: {
      "status": "Modbus connection failed",
      "requestaddress": 134613527,
      "requestnum": 62,
      "operation": "read",
      "group": "Contro
    [07.12.2020] [08:58:00] [[33mTRACE[0m]: onControlInfoRecieved - Vi har læst i read/control
    [07.12.2020] [08:58:00] |[31;1mERROR[0m|: QuickApp crashed: fibaroapiHC3.lua:3032: expected closing quote for string at line 6 col 12
    fibaroapiHC3.lua:3032: expected closing quote for string at line 6 col 12
    stack traceback:
        fibaroapiHC3.lua:5350: in function <fibaroapiHC3.lua:5348>
        [C]: in function 'error'
        fibaroapiHC3.lua:3032: in function 'decode_error'
        fibaroapiHC3.lua:3114: in function 'parse'
        fibaroapiHC3.lua:3185: in function 'parse'
        fibaroapiHC3.lua:3231: in function 'decode'
        NilanQA.lua:222: in function 'onControlInfoRecieved'
        NilanQA.lua:120: in function 'callback'
        NilanQA.lua:161: in function 'success'
        fibaroapiHC3.lua:570: in function 'fun'
        fibaroapiHC3.lua:951: in function <fibaroapiHC3.lua:939>
        [C]: in function 'xpcall'
        fibaroapiHC3.lua:5347: in function 'startUp'
        fibaroapiHC3.lua:5371: in main chunk
        [C]: in function 'dofile'
        NilanQA.lua:32: in main chunk
    Program completed in 124.77 seconds (pid: 2138).
    Debugging session completed (traced 0 instructions).
     

    Edited by ChristianSogaard
    • 0
    Posted

    I'm happy to announce that I've created a QuickApp for Nilan machines with CTS700 and CTS602 motherboards, which gives access to almost all details and can be downloaded from my website:

    1.

    Please login or register to see this link.

    2.

    Please login or register to see this link.

    or from the Fibaro marketplace:

    1.

    Please login or register to see this link.

     (the status is "In review" at the moment)

    2.

    Please login or register to see this link.

     

    More details about them are available on my site: 

    Please login or register to see this link.

    Join the conversation

    You can post now and register later. If you have an account, sign in now to post with your account.

    Guest
    Answer this question...

    ×   Pasted as rich text.   Paste as plain text instead

      Only 75 emoji are allowed.

    ×   Your link has been automatically embedded.   Display as a link instead

    ×   Your previous content has been restored.   Clear editor

    ×   You cannot paste images directly. Upload or insert images from URL.

    ×
    ×
    • Create New...