Welcome! Log In Create A New Profile

Advanced

BV510 Smart Thermostat

BV510 Smart Thermostat
April 05, 2017 06:50PM
Hi All

I have created a self running smart thermostat using the BV510 board, I have programmed it as a device with fully functioning heating schedule storage and heating modes you'd expect from a modern smart thermostat, I have created an android app to communicate with a web service which relays updates and gets status like current room temperature, mode, active schedule, list of schedules etc for the android app to work.



Its working great with my boiler in place of my old 70's thermostat, just not got a screen yet.

I have ordered a screen and don't want a button control panel, does anyone know of a way I could use an encoder knob or analog pot with this board? The intention being that I retrieve the value from the knob and adjust my requestedTemperature variable, so just like turning a dial on a traditional thermostat.

Edit: I have written a file which could possibly work, but I don't have the encoder yet, its in the post, any comments more than welcome!

// Keyes Rotary Encoder Module input for BV510 connected as follows:
// ENCODER <---------> GPIO
//      CLK -------- b4
//       DT -------- b5
//       SW -------- (NOT IN USE)
//        + -------- 3v3
//      GND -------- GND

// include the lib_io.bas file
// #include "[www.byvac.com];

dim enc.run,enc.max,enc.min,enc.val
dim enc.clk,enc.dt

function enc.start(min,max)
   if enc.run <> 1 then
         enc.min = min
         enc.max = max
         enc.val = min
        //check for encoder movement every 100 ms
        taskadd("enc.check()",1,100,1)
   endif
endf

function enc.check()
    enc.clk = io_pinGet(*RB4())
    enc.dt = io_pinGet(*RB5())
    // Check if encoder has moved in clockwise direction
    if enc.dt > enc.clk then
        io_pinSet(*RB4(),1)
        io_pinSet(*RB5(),1)
        if enc.val < enc.max
            enc.val = enc.val + 1
        endif
        print "Encoder has moved clockwise, new value is "
        print enc.val
        print "\r\n\r\n"
    else
    // Check if encoder has moved in anti clockwise direction
        if enc.dt < enc.clk then
            io_pinSet(*RB4(),1)
            io_pinSet(*RB5(),1)
            if enc.val > enc.min then
                enc.val = enc.val - 1
            endif
            print "Encoder has moved anti clockwise, new value is "
            print enc.val
            print "\r\n\r\n"
        endif
    endif
endf


All help greatly appreciated!



Edited 2 time(s). Last edit at 04/06/2017 04:12PM by djmills.uk@gmail.com.
Re: BV510 Smart Thermostat
April 06, 2017 05:44PM
What a great project, well done on the Android app that's always my stumbling block.

You have to stop the switch bounce on an encoder or you get poor results, it can be done is software but much easier in hardware.

This is the circuit I use, the pins also need weak pull ups activation. This particular encoder also has a push switch, hence the three wires.
The code I use to drive it is here:
The includes have been modified by the forum software, hover over them to see what they were and there is no ';' at the end.
// Rotary Encoder Example
// Cant set up as a library because of interrupt
//
// NOTES: rot.sw is 1 when not pressed and 0 when pressed, this will change
//        immediately the sw is pressed
//
// #include "[www.byvac.com];
// #include "[www.byvac.com];
//
constant ROTARY_A   {PORTB(PORT),3}
constant ROTARY_B   {PORTB(PORT),13}
constant ROTARY_SW  {PORTB(PORT),1}
//
dim rot.seqA, rot.seqB, rot.sw, rot.count
// *****************************************************************************
// *****************************************************************************
function rotary.start()
    io_pinRole(*ROTARY_A(),IN,WPU)
    io_pinRole(*ROTARY_B(),IN,WPU)
    io_pinRole(*ROTARY_SW(),IN,WPU)
    ir_io(*PORTB(),3,"rotary.irq",ROTARY_A(1))
    ir_io(*PORTB(),3,"rotary.irq",ROTARY_B(1))
    ir_io(*PORTB(),3,"rotary.irq",ROTARY_SW(1))
    rot.count = 0
    rot.sw = 1
endf

// *****************************************************************************
// rotary encoder interrupt, sets global vearibales
// *****************************************************************************
function rotary.irq()
    rot.sw = io_pinGet(*ROTARY_SW())
    //
    rot.seqA = rot.seqA << 1
    rot.seqA = rot.seqA | io_pinGet(*ROTARY_A())
    rot.seqB = rot.seqB << 1
    rot.seqB = rot.seqB | io_pinGet(*ROTARY_B())
    //
    rot.seqA = rot.seqA & 0xf
    rot.seqB = rot.seqB & 0xf
    //
    if (rot.seqA = 9) && (rot.seqB = 3) then
        rot.count = rot.count - 1
    endif
    if (rot.seqA = 3) && (rot.seqB = 9) then
        rot.count = rot.count + 1
    endif
endf
This works really well but I must confess that I got the idea of using 3 and 9 elsewhere, unfortunately I can't remember where. The code works in the background so you can set rot.count=0 and see if there is any change later on.

You may also find the code here "www.byvac.com/forum_images/rub1.bas" useful, its a menu system and number input using rotary. I have been working on a couple of RUB (Really Useful Boards) that just have a rotary input and a screen, hence all of the code. Ironically the laser cutter that I have been working on lately (on and of for the past 2 years) works best with push or touch buttons.
Re: BV510 Smart Thermostat
April 06, 2017 07:54PM
Excellent thanks! I think the encoder i got has all the nessecary circuits. I could be wrong. Its this one: [www.modmypi.com] i was hoping that i wouldnt have to modify this one. :). I got my display today. So thats gonna take me some tine to figure out lol. Ive so far had time to connect it and can see its detected by the i2cf command as 120 but thats all so far.

Kuman 0.96 Inch White IIC OLED Moudle I2c IIC Serial 128x64 LCD Display for Arduino Raspberry pi KY34-W [www.amazon.co.uk]
Re: BV510 Smart Thermostat
April 10, 2017 03:18PM
Hi Jim,

Got my encoder working using your code as a template, all working great including the SW line for changing thermostat mode, works great!
The display is also working, thanks for the code from the other topic for that :)

Dion

Re: BV510 Smart Thermostat
April 10, 2017 04:32PM
Dion,
the protect is interesting and the display looks really nice (with a flame). It may be worth writing it up if you have the time? Instructables is a good platform
Re: BV510 Smart Thermostat
April 10, 2017 05:12PM
Thanks jim. The flame is for when the boiler is running (relay a is on) i will try to get time to write it up of course.
Re: BV510 Smart Thermostat
April 18, 2017 03:11PM
I have installed this as my thermostat in my living room now, to see how it goes, I'm having a few strange issues, for starters the Date/Time, I was just running an repeating task every 60 seconds to add 1 minute to the date time. I do have an rtc but I'm unclear about which connections to make to the serial as I'm already using i2c for the screen.

dim thSettingTemp(6)
dim ActivationTemp, CurrentTemp, HeatingActive, Run, date_time(8), boost_end(8)
dim lastSecs#, runMode, HeatSwitch, restBusy, ActiveSchedule, prevSetting
dim isDebug, tpaBusy
...
function timeSync()
    if restBusy = 0 then
        dim newdate$[80]
        newdate$ = wifi.dt$()
        if newdate$ <> "" then
            newdate$ = dt.bst$(newdate$)
            dt.time(newdate$,*date_time())
        endif
    endif
endf
...
function startup()
...
//Set initial time (IMPORTANT not to be empty so needs this)
dt.time("Fri, 31 Mar 2017 13:09:00",*date_time())
timeSync()
taskadd("clock()",1,60000,1)
...
endf
...
function clock()
   dim newDate
   newDate = dt.UTC(*date_time())
   newDate = newDate + 60
   dt.UTC2time(newDate,*date_time())
   th.disp.updtime(*date_time()) //this is just to update the time/date on the display, works fine
endf


but somehow that ends up running ahead of time??? this of course makes the scheduling useless as the time is always going wrong. very odd, the other problem is that the encoder keeps failing to respond needing the device to be rebooted, I have noticed the serial program reporting 'error in devices()' when this happens.

encoder code:
// Cant set up as a library because of interrupt
//
// NOTES: rot.sw is 1 when not pressed and 0 when pressed, this will change
//        immediately the sw is pressed
//
// #include "c:\ByPic\lib\lib_intr.bas"
//

constant ROTARY_SW  {PORTB(PORT),1}
//
dim rot.seqA, rot.seqB, rot.sw, rot.min, rot.max, rot.prevSW, rot.updatePending
// *****************************************************************************
// *****************************************************************************
function rotary.start(min,max)
    rot.updatePending = 0
    io_pinRole(*RB4(),IN,WPU) //CLK
    io_pinRole(*RB5(),IN,WPU)  //DT
    io_pinRole(*RB2(),IN,WPU)  //SW
    ir_io(*PORTB(),3,"rotary.irq",RB4(1))
    ir_io(*PORTB(),3,"rotary.irq",RB5(1))
    ir_io(*PORTB(),3,"rotary.irq",RB2(1))
    rot.sw = 1
    rot.min = min
    rot.max = max
    taskadd("rotary.updateThermostat()",5,100,1)
endf

function rotary.updateThermostat()
    if rot.updatePending = 1 then
        rot.updatePending = 0
        dim t
        t = ActivationTemp / 100
        th.disp.updlevel(t)
    endif
endf

// *****************************************************************************
// rotary encoder interrupt, sets global vearibales
// *****************************************************************************
function rotary.irq()
    rot.sw = io_pinGet(*RB2())
    //
    rot.seqA = rot.seqA << 1
    rot.seqA = rot.seqA | io_pinGet(*RB4())
    rot.seqB = rot.seqB << 1
    rot.seqB = rot.seqB | io_pinGet(*RB5())
    //
    rot.seqA = rot.seqA & 0xf
    rot.seqB = rot.seqB & 0xf
    //
             dim temp
            temp = ActivationTemp / 100
            if (rot.seqA = 9) && (rot.seqB = 3) then
                if temp > rot.min then
                    ActivationTemp = ActivationTemp - 100
                    rot.updatePending = 1
                    //taskadd("th.temp.set()",5,0,0)
                endif
            endif
            if (rot.seqA = 3) && (rot.seqB = 9) then
                if temp < rot.max then
                    ActivationTemp = ActivationTemp + 100
                    rot.updatePending = 1
                    //taskadd("th.temp.set()",5,0,0)
                endif
            endif
    if rot.sw <> rot.prevSW then
        rot.prevSW = rot.sw
        if rot.prevSW = 0 then
            if th.setting.get(0) >= 2 then
                th.mode.set(0)
            else
                th.mode.set(th.setting.get(0) + 1)
            endif
        endif
    endif
endf



Edited 2 time(s). Last edit at 04/18/2017 03:17PM by djmills.uk@gmail.com.
Re: BV510 Smart Thermostat
April 18, 2017 04:01PM
A couple of things.

The scheduler is not a very good timekeeper as its purpose is to schedule tasks when it can, also if any other program is running in a loop then this will effect the time keeping. The two alternatives are use a timer or use the RTC that you have. I would go for the RTC as it is purpose designed for the job, also if it is the type with an EEPROM, you can keep your schedules in there which is handy. (http://www.bypic.co.uk/index.php/I2C#rtc)

To use, simply add it to the I2C bus, providing all of the addresses are different they will work together.

ROT works on an interrupt and all interrupts are cleared on an error, that is why it stops working. You can restart it after an error (I used rotary.start()) you will need to separate out the three 'ir_io(*PORTB(),3,"rotary.irq",RB4(n))' for a re-start.

Just a suggestion but it may be easier to debug if you kept the ROT as a separate entity and put the ActivationTemp adjustment in a separate function, you can still monitor rot.count for any changes.

Jim
Re: BV510 Smart Thermostat
April 18, 2017 05:41PM
Thanks jim, ill certainly go for using the rtc, how do I detect when the encoder error has occurred?



Edited 1 time(s). Last edit at 04/19/2017 08:54AM by djmills.uk@gmail.com.
Re: BV510 Smart Thermostat
April 19, 2017 03:22PM
In mine I didn't, I just put rotary.start() at the top of a function that used it. However when fully debugged there is unlikely to be any errors so is less of a problem.
Re: BV510 Smart Thermostat
April 22, 2017 10:36AM
Thanks for you help jim. Its all working now. Ive added the rtc onto the i2c connnection along with the display. I already had a place to store my schedules in the flash memory but am using the rtc memory to store the thermostat mode and temperature level setting which is working great. I still have a small issue of the tpa() stopping working sometimes. But apart from that its great.
Sorry, only registered users may post in this forum.

Click here to login