diff --git a/Makefile b/Makefile
index d71dd5bea4..d9319efa68 100644
--- a/Makefile
+++ b/Makefile
@@ -108,6 +108,7 @@ GENERATED_FILES += qapi/qapi-types-tpm.h qapi/qapi-types-tpm.c
 GENERATED_FILES += qapi/qapi-types-trace.h qapi/qapi-types-trace.c
 GENERATED_FILES += qapi/qapi-types-transaction.h qapi/qapi-types-transaction.c
 GENERATED_FILES += qapi/qapi-types-ui.h qapi/qapi-types-ui.c
+GENERATED_FILES += qapi/qapi-types-stimulate.h qapi/qapi-types-stimulate.c
 GENERATED_FILES += qapi/qapi-builtin-visit.h qapi/qapi-builtin-visit.c
 GENERATED_FILES += qapi/qapi-visit.h qapi/qapi-visit.c
 GENERATED_FILES += qapi/qapi-visit-block-core.h qapi/qapi-visit-block-core.c
@@ -126,6 +127,7 @@ GENERATED_FILES += qapi/qapi-visit-tpm.h qapi/qapi-visit-tpm.c
 GENERATED_FILES += qapi/qapi-visit-trace.h qapi/qapi-visit-trace.c
 GENERATED_FILES += qapi/qapi-visit-transaction.h qapi/qapi-visit-transaction.c
 GENERATED_FILES += qapi/qapi-visit-ui.h qapi/qapi-visit-ui.c
+GENERATED_FILES += qapi/qapi-visit-stimulate.h qapi/qapi-visit-stimulate.c
 GENERATED_FILES += qapi/qapi-commands.h qapi/qapi-commands.c
 GENERATED_FILES += qapi/qapi-commands-block-core.h qapi/qapi-commands-block-core.c
 GENERATED_FILES += qapi/qapi-commands-block.h qapi/qapi-commands-block.c
@@ -143,6 +145,7 @@ GENERATED_FILES += qapi/qapi-commands-tpm.h qapi/qapi-commands-tpm.c
 GENERATED_FILES += qapi/qapi-commands-trace.h qapi/qapi-commands-trace.c
 GENERATED_FILES += qapi/qapi-commands-transaction.h qapi/qapi-commands-transaction.c
 GENERATED_FILES += qapi/qapi-commands-ui.h qapi/qapi-commands-ui.c
+GENERATED_FILES += qapi/qapi-commands-stimulate.h qapi/qapi-commands-stimulate.c
 GENERATED_FILES += qapi/qapi-events.h qapi/qapi-events.c
 GENERATED_FILES += qapi/qapi-events-block-core.h qapi/qapi-events-block-core.c
 GENERATED_FILES += qapi/qapi-events-block.h qapi/qapi-events-block.c
@@ -160,6 +163,7 @@ GENERATED_FILES += qapi/qapi-events-tpm.h qapi/qapi-events-tpm.c
 GENERATED_FILES += qapi/qapi-events-trace.h qapi/qapi-events-trace.c
 GENERATED_FILES += qapi/qapi-events-transaction.h qapi/qapi-events-transaction.c
 GENERATED_FILES += qapi/qapi-events-ui.h qapi/qapi-events-ui.c
+GENERATED_FILES += qapi/qapi-events-stimulate.h qapi/qapi-events-stimulate.c
 GENERATED_FILES += qapi/qapi-introspect.c qapi/qapi-introspect.h
 GENERATED_FILES += qapi/qapi-doc.texi
 
@@ -611,6 +615,7 @@ qapi/qapi-types-tpm.c qapi/qapi-types-tpm.h \
 qapi/qapi-types-trace.c qapi/qapi-types-trace.h \
 qapi/qapi-types-transaction.c qapi/qapi-types-transaction.h \
 qapi/qapi-types-ui.c qapi/qapi-types-ui.h \
+qapi/qapi-types-stimulate.c qapi/qapi-types-stimulate.h \
 qapi/qapi-builtin-visit.c qapi/qapi-builtin-visit.h \
 qapi/qapi-visit.c qapi/qapi-visit.h \
 qapi/qapi-visit-block-core.c qapi/qapi-visit-block-core.h \
@@ -629,6 +634,7 @@ qapi/qapi-visit-tpm.c qapi/qapi-visit-tpm.h \
 qapi/qapi-visit-trace.c qapi/qapi-visit-trace.h \
 qapi/qapi-visit-transaction.c qapi/qapi-visit-transaction.h \
 qapi/qapi-visit-ui.c qapi/qapi-visit-ui.h \
+qapi/qapi-visit-stimulate.c qapi/qapi-visit-stimulate.h \
 qapi/qapi-commands.h qapi/qapi-commands.c \
 qapi/qapi-commands-block-core.c qapi/qapi-commands-block-core.h \
 qapi/qapi-commands-block.c qapi/qapi-commands-block.h \
@@ -646,6 +652,7 @@ qapi/qapi-commands-tpm.c qapi/qapi-commands-tpm.h \
 qapi/qapi-commands-trace.c qapi/qapi-commands-trace.h \
 qapi/qapi-commands-transaction.c qapi/qapi-commands-transaction.h \
 qapi/qapi-commands-ui.c qapi/qapi-commands-ui.h \
+qapi/qapi-commands-stimulate.c qapi/qapi-commands-stimulate.h \
 qapi/qapi-events.c qapi/qapi-events.h \
 qapi/qapi-events-block-core.c qapi/qapi-events-block-core.h \
 qapi/qapi-events-block.c qapi/qapi-events-block.h \
@@ -663,6 +670,7 @@ qapi/qapi-events-tpm.c qapi/qapi-events-tpm.h \
 qapi/qapi-events-trace.c qapi/qapi-events-trace.h \
 qapi/qapi-events-transaction.c qapi/qapi-events-transaction.h \
 qapi/qapi-events-ui.c qapi/qapi-events-ui.h \
+qapi/qapi-events-stimulate.c qapi/qapi-events-stimulate.h \
 qapi/qapi-introspect.h qapi/qapi-introspect.c \
 qapi/qapi-doc.texi: \
 qapi-gen-timestamp ;
diff --git a/Makefile.objs b/Makefile.objs
index c6c9b8fc21..c6806ed83c 100644
--- a/Makefile.objs
+++ b/Makefile.objs
@@ -20,6 +20,7 @@ util-obj-y += qapi/qapi-types-tpm.o
 util-obj-y += qapi/qapi-types-trace.o
 util-obj-y += qapi/qapi-types-transaction.o
 util-obj-y += qapi/qapi-types-ui.o
+util-obj-y += qapi/qapi-types-stimulate.o
 util-obj-y += qapi/qapi-builtin-visit.o
 util-obj-y += qapi/qapi-visit.o
 util-obj-y += qapi/qapi-visit-block-core.o
@@ -38,6 +39,7 @@ util-obj-y += qapi/qapi-visit-tpm.o
 util-obj-y += qapi/qapi-visit-trace.o
 util-obj-y += qapi/qapi-visit-transaction.o
 util-obj-y += qapi/qapi-visit-ui.o
+util-obj-y += qapi/qapi-visit-stimulate.o
 util-obj-y += qapi/qapi-events.o
 util-obj-y += qapi/qapi-events-block-core.o
 util-obj-y += qapi/qapi-events-block.o
@@ -55,6 +57,7 @@ util-obj-y += qapi/qapi-events-tpm.o
 util-obj-y += qapi/qapi-events-trace.o
 util-obj-y += qapi/qapi-events-transaction.o
 util-obj-y += qapi/qapi-events-ui.o
+util-obj-y += qapi/qapi-events-stimulate.o
 util-obj-y += qapi/qapi-introspect.o
 
 chardev-obj-y = chardev/
@@ -150,6 +153,7 @@ common-obj-y += qapi/qapi-commands-tpm.o
 common-obj-y += qapi/qapi-commands-trace.o
 common-obj-y += qapi/qapi-commands-transaction.o
 common-obj-y += qapi/qapi-commands-ui.o
+common-obj-y += qapi/qapi-commands-stimulate.o
 common-obj-y += qapi/qapi-introspect.o
 common-obj-y += qmp.o hmp.o
 endif
diff --git a/Makefile.target b/Makefile.target
index d0ec77a307..6ecd09321a 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -139,6 +139,7 @@ obj-y += memory.o
 obj-y += memory_mapping.o
 obj-y += dump.o
 obj-y += migration/ram.o
+obj-y += stimulate.o
 LIBS := $(libs_softmmu) $(LIBS)
 
 # Hardware support
diff --git a/hw/arm/microbit.c b/hw/arm/microbit.c
index b61d0747fe..2fdb1d01a6 100644
--- a/hw/arm/microbit.c
+++ b/hw/arm/microbit.c
@@ -16,12 +16,17 @@
 static void microbit_init(MachineState *machine)
 {
     DeviceState *dev;
+    NRF51State * soc;
 
     dev = qdev_create(NULL, TYPE_NRF51_SOC);
     if (machine->kernel_filename) {
         qdev_prop_set_string(dev, "kernel-filename", machine->kernel_filename);
     }
     object_property_set_bool(OBJECT(dev), true, "realized", &error_fatal);
+
+    soc = NRF51_SOC(dev);
+    object_property_add_alias(OBJECT(machine), "button-a", OBJECT(soc->nvic), "unnamed-gpio-in[17]", &error_fatal);
+    object_property_add_alias(OBJECT(machine), "button-b", OBJECT(soc->nvic), "unnamed-gpio-in[26]", &error_fatal);
 }
 
 static void microbit_machine_init(MachineClass *mc)
diff --git a/qapi/qapi-schema.json b/qapi/qapi-schema.json
index 25bce78352..0f506ca6f1 100644
--- a/qapi/qapi-schema.json
+++ b/qapi/qapi-schema.json
@@ -93,3 +93,4 @@
 { 'include': 'trace.json' }
 { 'include': 'introspect.json' }
 { 'include': 'misc.json' }
+{ 'include': 'stimulate.json' }
diff --git a/qapi/stimulate.json b/qapi/stimulate.json
new file mode 100644
index 0000000000..5ff9c73ff8
--- /dev/null
+++ b/qapi/stimulate.json
@@ -0,0 +1,24 @@
+# -*- Mode: Python -*-
+
+##
+# @ButtonPress:
+#
+# @identifier:  Name of the button.
+# @pushed_down: State of the button.
+#
+##
+{ 'struct': 'ButtonPress',
+  'data': {
+    'identifier': 'str',
+    'pushed_down': 'bool'
+     } }
+    
+##
+# @buttons-set-state:
+#
+# @buttons: List of updated button states.
+#
+# Returns: nothing in case of success
+##
+{ 'command': 'buttons-set-state',
+  'data': { 'buttons': ['ButtonPress'] } }
diff --git a/stimulate.c b/stimulate.c
new file mode 100644
index 0000000000..0bca40cd22
--- /dev/null
+++ b/stimulate.c
@@ -0,0 +1,56 @@
+/*
+ * stimulate.c
+ *
+ * Copyright (C) 2018 Steffen Görtz <contrib@steffen-goertz.de>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+#include "qemu-common.h"
+#include "qemu/log.h"
+#include "qom/object.h"
+#include "hw/qdev-core.h"
+#include "hw/boards.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-stimulate.h"
+
+#ifndef DEBUG_STIMULATE
+#define DEBUG_STIMULATE 1
+#endif
+
+#define DPRINTF(fmt, ...) do {                                           \
+    if (DEBUG_STIMULATE) {                                               \
+        qemu_log("stimulate: " fmt , ## __VA_ARGS__);                    \
+    }                                                                    \
+} while (0);
+
+void qmp_buttons_set_state(ButtonPressList *buttons, Error **errp)
+{
+    for (; buttons; buttons = buttons->next) {
+        if (buttons->value) {
+            DPRINTF("Set button %s to %s", buttons->value->identifier,
+                    buttons->value->pushed_down ? "true" : "false");
+
+            gchar *name = g_strdup_printf("button-%s",
+                    buttons->value->identifier);
+            Object *child = object_resolve_path_component(
+                    OBJECT(current_machine), name);
+
+            if (!child) {
+                error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+                        "GPIO '%s' doesn't exists", name);
+                g_free(name);
+                return;
+
+            } else {
+                g_free(name);
+                qemu_set_irq(OBJECT_CHECK(struct IRQState, (child), TYPE_IRQ),
+                        buttons->value->pushed_down);
+
+            }
+        }
+    }
+}
