The popularity and proliferation of the Internet of Things (IoT) paradigm is resulting a growing number of devices connect to the Internet. These devices are generating and consuming unprecedented amounts data at the edges of the infrastructure, and are enabling new classes of data-driven applications. Current approaches rely on cloud platforms located at the core of the infrastructure to process data. As the number of devices and the amount of data they generate and consume increases, such core-centric approaches are becoming increasingly inefficient. Furthermore, the latencies associated with transferring data between the edge and the core may prevent supporting time-critical applications. We propose an edge-based programming framework that allows users to define how data streams are processed based on the content and the location of the data. This enables the definition of data-driven reactive behaviors that can effectively exploit data patterns to dynamically drive stream processing, leveraging resources located at the edges of the infrastructure. Using a smart-city application use case, we illustrate that the presented programming system can support data-driven stream processing using edge resources. In terms of scalability, our experiments show that the system can scale to hundreds of nodes while keeping overheads low.