To meet increasingly restrictive requirements and improve quality of service (QoS), Internet of Things (IoT) systems have embraced multi-layered architectures leveraging edge and fog computing. However, the dynamic and changing IoT environment can impact QoS due to unexpected events. Therefore, proactive evolution and adaptation of the IoT system becomes a necessity and concern. In this paper, we present a model-based approach for the specification and execution of self-adaptive multi-layered IoT systems. Our proposal comprises the design of a domain-specific language (DSL) for the specification of such architectures, and a runtime framework to support the system behaviuor and its self-adaptation at runtime. The code for the deployment of the IoT system and the execution of the runtime framework is automatically produced by our prototype code generator. Moreover, we also show and validate the extensibility of such DSL by applying it to the domain of underground mining. The complete infrastructure (modeling tool, generator and runtime components) is available in a online open source repository.