Event-driven programming is a popular paradigm for programming sensor nodes. It is based on the specification of actions (also known as event handlers) which are triggered by the occurrence of events. While this approach is both simple and efficient, it suffers from two important limitations. Firstly, the association of events to actions is static - there is no explicit support for adopting this association depending on the program state. Secondly, a program is split up into many distinct actions without explicit support for sharing information among these, except through global variables. These limitations often lead to issues with code modularity, complexity, and correctness. To tackle these issues we propose OSM, a programming model and language for sensor nodes based on finite state machines. By extending the event paradigm with states and transitions between them, state-based programming supports a dynamic association of events to actions. For removing the second limitation, OSM introduces state attributes that allow sharing of information among actions. They can be considered local variables of a state with support for automatic memory management. OSM specifications can be compiled into sequential C code that requires only minimal runtime support, resulting in efficient and compact systems.