Mysensor-ing a thermostatic valve



  • Hi,

    I need to control several heaters in my house.
    I thought about z-wave thermostatic valves such as Danfoss or Stella-Z.... but, well... the price is a bitter pill.

    And while thinking about alternatives possible solution, i came across this page:
    https://piontecsmumble.wordpress.com/2013/02/25/openhr-20-tutorial-part-0-introduction/

    The clevers guys who didi this hack really desserve warm congratulations. I am impressed.

    And i wonder... Do you think we could fit a nrf24 in the casing instead of the rfm12 ?
    And do you think we could flash a mysensor sketch in the atmega 169 ?

    I don't feel expert enough to start this adventure by myself... But if someone is willing to test with me, i'll be glad to help.


  • Hero Member

    Some pretty cool hacking going on there!

    Q: How/where do you want to control/use the data? Why not just use the hack as they have done and bring the received data into the mysensors ( or directly into your end solution)

    i think to do via mysensors would cost more to do as its more complicated network thus needs more software mods



  • I have ordered 2 HR25 valves.
    these valves are an update of the HR20 with a atmega329 instead of 169.

    My idea is the following:
    The easy part (widely documented).

    • connect an ISP connecto to the PCB.
    • connect an NRF24L01 to the PCB

    The harder part:

    • use the atmega329 with arduino boatloader and framework: Probably doable, but not natively supported. Might need some tweaking in the bootloader sources.
    • flash the atmega with a simple mysensor sketch as proof of concept.

    Then, the development step by step:

    • First a simple mysensor actuator wich will directly operate the valve motor.
    • Following step: get the internal temperature sensor working
    • Then: integrate PID control loop. -> The setting point would be given over the air by MySensor controller
    • Then use the internal LCD and buttons for local control. The LCD library of openHR (AVR C) is probably a good starting point.

  • Admin

    Why do you want to use the bootloader? For ota updating of the code? If not then the bootloader is not necessary. You have the ISP available and the tools to access it.



  • That's right. I don't need the bootloader itself.

    edit:
    This a memo for myself :
    http://www.instructables.com/id/Arduino-on-all-sorts-of-Atmels/?ALLSTEPS
    Atmega3290 is supported and is pretty close of atmega 329.



  • Hey guys,
    Some news,

    I have received 2 HR25 TRV.
    I have tried to connect an ISP header to one of them.
    The good news is: MISO/MOSI/SCK/GND/VCC./and RESET are easily available on the upper part of the PCB. (SPI pins are used for the 3 buttons and power and reset are already available on the Jtag header.
    The bad news is that it is quite easy to damge the pcb while welding. I have had a problem with two coppers traces that went away of the PCB... probably because of overheat. Theses traces were so thin, that until now i hav not been able to weld a jumper to repair them.
    However , i will try again tonight.

    Regarding the software, i think i have been able to set-up the arduino IDE to compile for an atmega329p target. I have to test it to validate the process.



  • Hi there,

    I have been able to make some progress.
    The cutted traces have been repaired with some thin wire. However, this board is definitely damaged. I think this one will remain my "guinea pig".

    after repairing the traces, i have tested the isp connection:

    sorg@samsung-ubuntu:~$ avrdude -c usbasp -p m329p
       
    avrdude: warning: cannot set sck period. please check for usbasp firmware update.   
    avrdude: AVR device initialized and ready to accept instructions
      
    Reading | ################################################## | 100% 0.00s
    avrdude: Device signature = 0x1e950b
    avrdude: safemode: Fuses OK (E:FD, H:91, L:62)
    avrdude done.  Thank you.
    

    😍

    No it's time to set-up the arduino IDE for compiling...

    in my Arduino/hardware/boards.txt, i have hadded the following lines:
    ##############################################################

    hr25.name=HoneyWell HR25 Thermostat/ programming with USBasp
    hr25.upload.using=USBasp
    hr25.upload.protocol=usb
    hr25.upload.maximum_size=30720
    hr25.upload.speed=38400
    
    hr25.build.mcu=atmega329p
    hr25.build.f_cpu=16000000L
    hr25.build.core=arduino
    hr25.build.variant=hr25
    

    Then, i have created a new folder named "hr25" in Arduino/hardware/variants , and in this folder i create a file named pins_arduino.h and put the following inside:

    /*
      pins_arduino.h - Pin definition functions for Arduino
      Part of Arduino - http://www.arduino.cc/
    
      Copyright (c) 2007 David A. Mellis
    
      This library is free software; you can redistribute it and/or
      modify it under the terms of the GNU Lesser General Public
      License as published by the Free Software Foundation; either
      version 2.1 of the License, or (at your option) any later version.
    
      This library is distributed in the hope that it will be useful,
      but WITHOUT ANY WARRANTY; without even the implied warranty of
      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      Lesser General Public License for more details.
    
      You should have received a copy of the GNU Lesser General
      Public License along with this library; if not, write to the
      Free Software Foundation, Inc., 59 Temple Place, Suite 330,
      Boston, MA  02111-1307  USA
    
      ***************************************
      Definition for ATmega329p as in the HR25 thermostat
    */
    
    #ifndef Pins_Arduino_h
    #define Pins_Arduino_h
    
    #include <avr/pgmspace.h>
    
    #define NUM_DIGITAL_PINS            53
    #define NUM_ANALOG_INPUTS           8
    #define analogInputToDigitalPin(p)  ((p < 8) ? (p) + 40 : -1)
    #define digitalPinHasPWM(p)         ((p) == 12 || (p) == 14 || (p) == 15 || (p) == 13)
    
    
    static const uint8_t SS   = 8; 		//PB0
    static const uint8_t MOSI = 10;		//PB2
    static const uint8_t MISO = 11;		//PB3
    static const uint8_t SCK  = 9;		//PB1
    
    static const uint8_t SDA = 37;		//PE5
    static const uint8_t SCL = 36;		//PE4
    // #define LED_BUILTIN 13
    
    static const uint8_t A0 = 40;		//PF0
    static const uint8_t A1 = 41;		//PF1
    static const uint8_t A2 = 42;		//PF2
    static const uint8_t A3 = 43;		//PF3
    static const uint8_t A4 = 44;		//PF4
    static const uint8_t A5 = 45;		//PF5
    static const uint8_t A6 = 46;		//PF6
    static const uint8_t A7 = 47;		//PF7
    
    // Not sure of that... atmega168 use PCICR whereas the atmegaxx9 seems to use a EIMSK register... Will it work ?
    #define digitalPinToPCICR(p)    ( (((p) >= 32) && ((p) <= 39)) ||  (((p) >= 8) && ((p) <= 15)) ? (&EIMSK) : \
    								((uint8_t *)0) ) )
    								
    #define digitalPinToPCICRbit(p) ( (((p) >= 32) && ((p) <= 39)) ? 4 : \
    								( (((p) >= 8) && ((p) <= 15)) ? 5 : \
    								((uint8_t *)0) ) )
    								
    #define digitalPinToPCMSK(p)    ( (((p) >= 32) && ((p) <= 39)) ? (&PCMSK0) : \
    								( (((p) >= 8) && ((p) <= 15)) ? (&PCMSK1) : \
    								((uint8_t *)0) ) )
    								
    #define digitalPinToPCMSKbit(p) ( (((p) >= 32) && ((p) <= 39)) ? ((p) - 32) : \
    								( (((p) >= 8) && ((p) <= 15)) ? ((p) - 8) : \
    								((uint8_t *)0) ) )
    								
    #define digitalPinToInterrupt(p)  ((p) == 24 ? 0 : NOT_AN_INTERRUPT)
    
    #ifdef ARDUINO_MAIN
    
    // these arrays map port names (e.g. port B) to the
    // appropriate addresses for various functions (e.g. reading
    // and writing)
    const uint16_t PROGMEM port_to_mode_PGM[] = {
    	NOT_A_PORT,
    	(uint16_t) &DDRA,
    	(uint16_t) &DDRB,
    	(uint16_t) &DDRC,
    	(uint16_t) &DDRD,
    	(uint16_t) &DDRE,
    	(uint16_t) &DDRF,
    	(uint16_t) &DDRG,
    };
    
    const uint16_t PROGMEM port_to_output_PGM[] = {
    	NOT_A_PORT,
    	(uint16_t) &PORTA,
    	(uint16_t) &PORTB,
    	(uint16_t) &PORTC,
    	(uint16_t) &PORTD,
    	(uint16_t) &PORTE,
    	(uint16_t) &PORTF,
    	(uint16_t) &PORTG,
    };
    
    const uint16_t PROGMEM port_to_input_PGM[] = {
    	NOT_A_PORT,
    	(uint16_t) &PINA,
    	(uint16_t) &PINB,
    	(uint16_t) &PINC,
    	(uint16_t) &PIND,
    	(uint16_t) &PINE,
    	(uint16_t) &PINF,
    	(uint16_t) &PING,
    };
    
    const uint8_t PROGMEM digital_pin_to_port_PGM[] = {
    	PA,	 // 0					// LCD_Com0
    	PA,							// LCD_Com1
    	PA,							// LCD_Com2
    	PA,
    	PA,							// LCD_Seg0
    	PA,							// LCD_Seg1
    	PA,							// LCD_Seg2
    	PA,							// LCD_Seg3
    
    	PB,	 // 8 - NSS - PCINT8	// Contact - Thermostat installed on the valve
    	PB,  // 9 - SCK - PCINT9	// KEY °C
    	PB,  // 10 - MOSI - PCINT10	// KEY Prog
    	PB,  // 11 - MISO - PCINT11	// KEY Auto/Manu
    	PB,  // 12 - PWM - PCINT12	// H-Bridge 1
    	PB,  // 13 - PWM - PCINT13	// Incremental coder A
    	PB,  // 14 - PWM - PCINT14	// Incremental coder B
    	PB,  // 15 - PWM - PCINT15	// H-Bridge 2
    	
    	PC,	 // 16					// LCD_Seg12
    	PC,	 // 17					// LCD_Seg11
    	PC,	 // 18					// LCD_Seg10
    	PC,	 // 19					// LCD_Seg9
    	PC,	 // 20					// LCD_Seg8
    	PC,	 // 21					// LCD_Seg7
    	PC,	 // 22					// LCD_Seg6
    	PC,	 // 23					// LCD_Seg5
    
    	PD,  // 24 - INT0
    	PD,	 // 25					// LCD_Seg21
    	PD,	 // 26					// LCD_Seg20
    	PD,	 // 27					// LCD_Seg19
    	PD,	 // 28					// LCD_Seg18
    	PD,	 // 29					// LCD_Seg17
    	PD,	 // 30					// LCD_Seg16
    	PD,	 // 31					// LCD_Seg15
    
    	PE,	 // 32 - RXD - PCINT0	// Header Pin7
    	PE,	 // 33 - TXD - PCINT1	// Header Pin6
    	PE,	 // 34 - PCINT2			// Header Pin2
    	PE,	 // 35 - PCINT3			// Activate reflective sensor
    	PE,	 // 36 - SCL - PCINT4	// Reflective sensor output
    	PE,	 // 37 - SDA - PCINT5
    	PE,	 // 38 - PCINT6
    	PE,	 // 39 - PCINT7
    
    	PF,	 // 40 - A0
    	PF,	 // 41 - A1
    	PF,	 // 42 - A2				// NTC measurement.
    	PF,	 // 43 - A3				// Activate NTC divider bridge
    	PF,	 // 44 - A4 - TCK		// Header Pin4
    	PF,	 // 45 - A5 - TMS		// Header Pin3
    	PF,	 // 46 - A6 - TDO		// Header Pin5
    	PF,	 // 47 - A7 - TDI		// Header Pin8
    	
    	PG,	 // 48					// LCD_Seg14
    	PG,	 // 49					// LCD_Seg13
    	PG,							// LCD_Seg4
    	PG,							// H-Bridge 3
    	PG,  // 52 					// H-Bridge 4
    	NOT_A_PORT,
    	NOT_A_PORT,
    	NOT_A_PORT,
    };
    
    const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = {
    	_BV(0), /* 0, port A */
    	_BV(1),
    	_BV(2),
    	_BV(3),
    	_BV(4),
    	_BV(5),
    	_BV(6),
    	_BV(7),
    
    	_BV(0), /* 8, port B */
    	_BV(1),
    	_BV(2),
    	_BV(3),
    	_BV(4),
    	_BV(5),
    	_BV(6),
    	_BV(7),
    
    	_BV(0), /* 16, port C */
    	_BV(1),
    	_BV(2),
    	_BV(3),
    	_BV(4),
    	_BV(5),
    	_BV(6),
    	_BV(7),
    
    	_BV(0), /* 24, port D */
    	_BV(1),
    	_BV(2),
    	_BV(3),
    	_BV(4),
    	_BV(5),
    	_BV(6),
    	_BV(7),
    
    	_BV(0), /* 32, port E */
    	_BV(1),
    	_BV(2),
    	_BV(3),
    	_BV(4),
    	_BV(5),
    	_BV(6),
    	_BV(7),
    
    	_BV(0), /* 40, port F */
    	_BV(1),
    	_BV(2),
    	_BV(3),
    	_BV(4),
    	_BV(5),
    	_BV(6),
    	_BV(7),
    
    	_BV(0), /* 48, port G */
    	_BV(1),
    	_BV(2),
    	_BV(3),
    	_BV(4),
    	NOT_A_PIN,
    	NOT_A_PIN,
    	NOT_A_PIN,
    };
    
    const uint8_t PROGMEM digital_pin_to_timer_PGM[] = {
    	NOT_ON_TIMER, 	/* 0  - PA0 */
    	NOT_ON_TIMER, 	/* 1  - PA1 */
    	NOT_ON_TIMER, 	/* 2  - PA2 */
    	NOT_ON_TIMER,  	/* 3  - PA3 */
    	NOT_ON_TIMER,	/* 4  - PA4 */
    	NOT_ON_TIMER, 	/* 5  - PA5 */
    	NOT_ON_TIMER, 	/* 6  - PA6 */
    	NOT_ON_TIMER,	/* 7  - PA7 */
    	
    	NOT_ON_TIMER, 	/* 8  - PB0 */
    	NOT_ON_TIMER, 	/* 9  - PB1 */
    	NOT_ON_TIMER, 	/* 10 - PB2 */
    	NOT_ON_TIMER, 	/* 11 - PB3 */
    	TIMER0A,	  	/* 12 - PB4 */
    	TIMER1A,	 	/* 13 - PB5 */
    	TIMER1B,	 	/* 14 - PB6 */
    	TIMER2A,	 	/* 15 - PB7 */
    	
    	NOT_ON_TIMER, 	/* 16 - PC0 */
    	NOT_ON_TIMER,	/* 17 - PC1 */
    	NOT_ON_TIMER,	/* 18 - PC2 */
    	NOT_ON_TIMER,	/* 19 - PC3 */
    	NOT_ON_TIMER,	/* 20 - PC4 */
    	NOT_ON_TIMER,	/* 21 - PC5 */
    	NOT_ON_TIMER,	/* 22 - PC6 */
    	NOT_ON_TIMER,	/* 23 - PC7 */
    	
    	NOT_ON_TIMER,	/* 24 - PD0 */
    	NOT_ON_TIMER,	/* 25 - PD1 */
    	NOT_ON_TIMER,	/* 26 - PD2 */
    	NOT_ON_TIMER,	/* 27 - PD3 */
    	NOT_ON_TIMER,	/* 28 - PD4 */
    	NOT_ON_TIMER,	/* 29 - PD5 */
    	NOT_ON_TIMER,	/* 30 - PD6 */
    	NOT_ON_TIMER,	/* 31 - PD7 */
    	
    	NOT_ON_TIMER,	/* 32 - PE0 */
    	NOT_ON_TIMER,	/* 33 - PE1 */
    	NOT_ON_TIMER,	/* 34 - PE2 */
    	NOT_ON_TIMER,	/* 35 - PE3 */
    	NOT_ON_TIMER,	/* 36 - PE4 */
    	NOT_ON_TIMER,	/* 37 - PE5 */
    	NOT_ON_TIMER,	/* 38 - PE6 */
    	NOT_ON_TIMER,	/* 39 - PE7 */
    	
    	NOT_ON_TIMER,	/* 40 - PF0 */
    	NOT_ON_TIMER,	/* 41 - PF1 */
    	NOT_ON_TIMER,	/* 42 - PF2 */
    	NOT_ON_TIMER,	/* 43 - PF3 */
    	NOT_ON_TIMER,	/* 44 - PF4 */
    	NOT_ON_TIMER,	/* 45 - PF5 */
    	NOT_ON_TIMER,	/* 46 - PF6 */
    	NOT_ON_TIMER,	/* 47 - PF7 */
    	
    	NOT_ON_TIMER,	/* 48 - PG0 */
    	NOT_ON_TIMER,	/* 49 - PG1 */
    	NOT_ON_TIMER,	/* 50 - PG2 */
    	NOT_ON_TIMER,	/* 51 - PG3 */
    	NOT_ON_TIMER,	/* 52 - PG4 */
    	NOT_ON_TIMER,	/* 53 - PG5 dose not exist*/
    	NOT_ON_TIMER,	/* 54 - PG6 dose not exist*/
    	NOT_ON_TIMER	/* 55 - PG7 dose not exist*/
    };
    
    #endif
    
    // These serial port names are intended to allow libraries and architecture-neutral
    // sketches to automatically default to the correct port name for a particular type
    // of use.  For example, a GPS module would normally connect to SERIAL_PORT_HARDWARE_OPEN,
    // the first hardware serial port whose RX/TX pins are not dedicated to another use.
    //
    // SERIAL_PORT_MONITOR        Port which normally prints to the Arduino Serial Monitor
    //
    // SERIAL_PORT_USBVIRTUAL     Port which is USB virtual serial
    //
    // SERIAL_PORT_LINUXBRIDGE    Port which connects to a Linux system via Bridge library
    //
    // SERIAL_PORT_HARDWARE       Hardware serial port, physical RX & TX pins.
    //
    // SERIAL_PORT_HARDWARE_OPEN  Hardware serial ports which are open for use.  Their RX & TX
    //                            pins are NOT connected to anything by default.
    #define SERIAL_PORT_MONITOR   Serial
    #define SERIAL_PORT_HARDWARE  Serial
    
    #endif
    

    DISCLAIMER: The previous file has been created by myself by mixing several sources.I am notan arduino nor AVR expert, and I do not guarantee that everything is correct. Specificaly, i have some doubt about the pin change interupts... to be tested and improved.

    So once this file has been created, i can start arduino and create a simple "blink" sketch.

    /*
      Blink
      Turns on an LED on for one second, then off for one second, repeatedly.
    
      This example code is in the public domain.
     */
    
    int led = 34; // pin 34 = PE2, a pin exposed on the connector of the TRV.
    
    // the setup routine runs once when you press reset:
    void setup() {                
      // initialize the digital pin as an output.
      pinMode(led, OUTPUT);     
    }
    
    // the loop routine runs over and over again forever:
    void loop() {
      digitalWrite(led, HIGH);   // turn the LED on (HIGH is the voltage level)
      delay(1000);               // wait for a second
      digitalWrite(led, LOW);    // turn the LED off by making the voltage LOW
      delay(1000);               // wait for a second
    }
    

    Menu Tool / Card Type, i select the HR25 entry. Then, i select file/ upload with programmer and voila !
    The sketch compile and is loaded through the isp pins.
    Then i can see the PE2 pin blinking... Howeer, the frequecy is not correct . Instead of blinking every 1s I have a blink every 8seconds... i guess i have a problem of frequency scaling.... to be investigated but it's a good start !



  • The fuses of th HR25 atmega are:

    E:FD, H:91, L:62

    If i trust the AVR duse calc: http://www.engbedded.com/fusecalc/
    This means that the 8-divider is applied on the clock... this might explain the behavious seen above.

    So i changed the CKDIV8 bit:

    avrdude -c usbasp -p m329p -U lfuse:w:0xe2:m
    

    and voila the pin 34 , blink à 1Hz.
    Frequency problem solved.



  • OK, some news....
    I have connected a rf24 module to the external header, hoping to drive it with softSPI (in order to limit internal modification of the valve).

    While compiling a simple mysensor sketch, i can see several issues with the libraries Lowpower.h and PinchangeInt.h.... these libraries are very MCU-dependant and are not compiling. It is probably doable to modify them in order to upport the 329p, but it is out of my field of competence. I don't really understand the internals of theses libs.
    If someone can help, it will be apreciated.


  • Admin

    These dependencies has been removed in the development branch.



  • @hek said:

    These dependencies has been removed in the development branch.

    Is that sure ? I have not tried to compile dev branch yet, but i still find a reference to lowpower in Mysensor.h :

    #ifdef __cplusplus
    #include <Arduino.h>
    #include <SPI.h>
    #include "utility/LowPower.h"
    #endif

  • Admin

    @Sorg

    Sorry.. I only read PinChangeInt. Still a Lowpower dependecy if you want to use the sleep functions.

    Might be good to make this as a "driver" as well in the future. But it will be hard because it is relatively hardware dependent if you want to wake up on external triggers.



  • @hek Sure.
    Modifying the lowpower library to manage the 329p is definitely doable but i need to understand the internals and read the MCU datasheet. Time consuming but doable.



  • Other general question:
    At this stage, is the "dev" branch compatible with a "stable" gateway and "stable" nodes ?


  • Admin

    Yes, it should.



  • @Sorg Hello, I am really interested in this topic, do you have any new informations or progress in this project ?



  • Hello Lucas,

    Last year , i did not achieve to run a sketch on the HR25. I remain convinced that it should be doable, but i am not enough aware of the inner details of the MCU / Arduino.
    also, my job has become a lot more time consuming, and i have not been able to spend time on this project for several months.

    If someone want to take over from here, i would be very happy.


Log in to reply
 

Suggested Topics

  • 87
  • 7
  • 7
  • 8
  • 2
  • 1

58
Online

11.4k
Users

11.1k
Topics

112.7k
Posts