Let’s first start with PCA9555’s behavior: if you take a look at PCA9555’s datasheet, its initial state is that every pin is in input mode with an internal pull-up resistor (about 100K). So this means right after power on all the pins will be in HIGH state. This persists until you send a command to set the pins to output mode and set them to LOW state. Normally the 100K pull-up resistor isn’t strong enough to drive a real load, but it is certainly sufficient for MOSFETs or even NPN transistors to turn them on, thus activating your relays.
To solve this problem, if you look at OpenSprinkler’s driver design:
it has 10K pull-down resistors on each zone, this will overcome the 100K internal pull-up resistor to make sure the pins are at LOW state at power-up.
Also, the initialization code:
calls apply_all_station_bits() function, which internally calls PCA9555’s functions to set the pins to output mode and set them to low.
Now, what I don’t know is whether your relay board is ‘active high’ or ‘active low’ type. Many common relay boards use ‘active low’, that means, a signal that’s LOW will activate relay. In that case, you actually want station_bits to be HIGH in order to deactivate the relay, and LOW to activate it. This is something you need to find out about your relay board because they are not all built the same.